Add CPU time processor

This commit is contained in:
Christophe Bedard 2019-07-29 12:56:58 +02:00
parent f7b368658a
commit 5eb175cfd4
4 changed files with 141 additions and 0 deletions

View file

@ -0,0 +1,64 @@
# Copyright 2019 Robert Bosch GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for CPU time events processing."""
from typing import Dict
from tracetools_read.utils import get_field
from .data_model.cpu_time import CpuTimeDataModel
from .handler import EventHandler
from .lttng_models import EventMetadata
class CpuTimeProcessor(EventHandler):
"""
Processor that extracts data for CPU time.
It extracts timestamps from sched_switch events to later compute CPU time per thread.
"""
def __init__(self) -> None:
# Link event to handling method
handler_map = {
'sched_switch':
self._handle_sched_switch,
}
super().__init__(handler_map)
self._data = CpuTimeDataModel()
# Temporary buffers
# cpu_id -> start timestamp of the running thread
self._cpu_start: Dict[int, int] = {}
def get_data_model(self) -> CpuTimeDataModel:
return self._data
def _handle_sched_switch(
self, event: Dict, metadata: EventMetadata
) -> None:
timestamp = metadata.timestamp
cpu_id = metadata.cpu_id
# Process if there is a previous thread timestamp
# TODO instead of discarding it, use first ever timestamp
# of the trace (with TraceCollection.timestamp_begin)
prev_timestamp = self._cpu_start.get(cpu_id, None)
if prev_timestamp is not None:
prev_tid = get_field(event, 'prev_tid')
duration = timestamp - prev_timestamp
self._data.add_duration(prev_tid, prev_timestamp, duration, cpu_id)
# Set start timestamp of next thread
self._cpu_start[cpu_id] = timestamp

View file

@ -0,0 +1,52 @@
# Copyright 2019 Robert Bosch GmbH
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for CPU time data model."""
import pandas as pd
class CpuTimeDataModel():
"""
Container to model pre-processed CPU time data for analysis.
Contains data for an analysis to use. It uses pandas DataFrames directly.
"""
def __init__(self) -> None:
"""Constructor."""
self.times = pd.DataFrame(columns=[
'tid',
'start_timestamp',
'duration',
'cpu_id',
])
def add_duration(
self, tid: int, start_timestamp: int, duration: int, cpu_id: int
) -> None:
data = {
'tid': tid,
'start_timestamp': start_timestamp,
'duration': duration,
'cpu_id': cpu_id,
}
self.times = self.times.append(data, ignore_index=True)
def print_model(self) -> None:
"""Debug method to print every contained df."""
print('====================CPU TIME DATA MODEL====================')
tail = 20
print(f'Times (tail={tail}):\n{self.times.tail(tail).to_string()}')
print('===========================================================')

View file

@ -21,9 +21,30 @@ from typing import Union
from pandas import DataFrame
from .data_model.cpu_time import CpuTimeDataModel
from .data_model.ros import RosDataModel
class CpuTimeDataModelUtil():
"""
CPU time data model utility class.
Provides functions to get info on a CPU time data model.
"""
def __init__(self, data_model: CpuTimeDataModel) -> None:
"""
Constructor.
:param data_model: the data model object to use
"""
self._data = data_model
def get_time_per_thread(self) -> DataFrame:
"""Get a DataFrame of total duration for each thread."""
return self._data.times.loc[:, ['tid', 'duration']].groupby(by='tid').sum()
class RosDataModelUtil():
"""
ROS data model utility class.

View file

@ -18,6 +18,7 @@
import argparse
import time
from tracetools_analysis.analysis import cpu_time_processor
from tracetools_analysis.analysis import load
from tracetools_analysis.analysis import ros2_processor
@ -37,8 +38,11 @@ def main():
events = load.load_pickle(pickle_filename)
processor = ros2_processor.ros2_process(events)
cpu_processor = cpu_time_processor.CpuTimeProcessor()
cpu_processor.handle_events(events)
time_diff = time.time() - start_time
print(f'processed {len(events)} events in {time_diff * 1000:.2f} ms')
processor.get_data_model().print_model()
cpu_processor.get_data_model().print_model()