Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ProcessTimer.cxx
Go to the documentation of this file.
1/*
2 * Project: RooFit
3 * Authors:
4 * ZW, Zef Wolffs, Nikhef, zefwolffs@gmail.com
5 * PB, Patrick Bos, Netherlands eScience Center, p.bos@esciencecenter.nl
6 *
7 * Copyright (c) 2022, CERN
8 *
9 * Redistribution and use in source and binary forms,
10 * with or without modification, are permitted according to the terms
11 * listed in LICENSE (http://roofit.sourceforge.net/license.txt)
12 */
13
15
16#include <iostream>
17#include <fstream>
18#include <iomanip> // setw
19
20using namespace std;
21
22namespace RooFit {
23namespace MultiProcess {
24
25/** \class ProcessTimer
26 *
27 * \brief Can be used to generate timings of multiple processes simultaneously and output logs
28 *
29 * This static class records timings of multiple processes simultaneously and allows for these
30 * timings to be written out in json format, one file for each process. Multiple overlapping
31 * sections can be timed independently on the same process. It also allows for the timings
32 * to be written out to json logfiles in a specified interval, for example every half hour.
33 *
34 * Note that this class logs timings in milliseconds.
35 */
36
37list<chrono::time_point<chrono::steady_clock>> ProcessTimer::get_durations(string to_return)
38{
39 ProcessTimer::duration_map_t::key_type sec_name;
40 ProcessTimer::duration_map_t::mapped_type duration_list;
41 for (auto const &durations_element : ProcessTimer::durations) {
42 std::tie(sec_name, duration_list) = std::move(durations_element);
43 if (sec_name != to_return)
44 continue;
45 else
46 return duration_list;
47 }
48 throw ::invalid_argument("section name " + to_return +
49 " not found in timer map, so it cannot"
50 " be retrieved");
51}
52
53void ProcessTimer::start_timer(string section_name)
54{
55 auto it = ProcessTimer::durations.find(section_name);
56 if (it == ProcessTimer::durations.end()) {
57 // Key does not exist in map yet, start the first timer of this section
58 ProcessTimer::durations.insert({section_name, {chrono::steady_clock::now()}});
59 } else if (it->second.size() % 2 != 0) {
60 // All even indices contain start times, if size of list is currently even we can not start a new timer
61 throw ::invalid_argument("Section name " + section_name +
62 " timer has already started, and was not stopped before calling `start_timer`");
63 } else {
64 // Add start time to list
65 it->second.push_back(chrono::steady_clock::now());
66 }
67}
68
69void ProcessTimer::end_timer(string section_name)
70{
71 auto it = ProcessTimer::durations.find(section_name);
72 if (it == ProcessTimer::durations.end()) {
73 // Key does not exist in map yet
74 throw ::invalid_argument("Section name " + section_name + " timer was never started!");
75 } else if (it->second.size() % 2 == 0) {
76 // All odd indices contain end times, if size of list is currently odd we can not start a new timer
77 throw ::invalid_argument("Section name " + section_name +
78 " timer does exist, but was not started before calling `end_timer`");
79 } else {
80 // Add end time to list
81 it->second.push_back(chrono::steady_clock::now());
82 }
83
84 // Write to file intermittently if interval is reached and write_interval is set
85 if (write_interval && (chrono::duration_cast<chrono::seconds>(chrono::steady_clock::now() - previous_write).count() >
87 previous_write = chrono::steady_clock::now();
90 }
91}
92
93void ProcessTimer::print_durations(string to_print)
94{
95 cout << "On PID: " << ProcessTimer::process << endl << "====================" << endl << endl;
96 ProcessTimer::duration_map_t::key_type sec_name;
97 ProcessTimer::duration_map_t::mapped_type duration_list;
98 for (auto const &durations_element : ProcessTimer::durations) {
99 std::tie(sec_name, duration_list) = std::move(durations_element);
100 if (to_print != "all" && sec_name != to_print)
101 continue; // continue if only asked for specific section
102
103 int i = 0;
104 long total_duration = 0;
105 cout << "Section name " << sec_name << ":" << endl;
106 for (auto it = duration_list.begin(); it != duration_list.end(); ++it) {
107 long duration = chrono::duration_cast<chrono::milliseconds>(*std::next(it) - *it).count();
108 cout << "Duration " << i << ": " << duration << "ms +" << endl;
109 total_duration += duration;
110 i++;
111 }
112 cout << "--------------------" << endl << "Total: " << total_duration << "ms" << endl << endl;
113 }
114}
115
117{
118 cout << "On PID: " << ProcessTimer::process << endl;
119 ProcessTimer::duration_map_t::key_type sec_name;
120 ProcessTimer::duration_map_t::mapped_type duration_list;
121 for (auto const &durations_element : ProcessTimer::durations) {
122 std::tie(sec_name, duration_list) = std::move(durations_element);
123 int i = 0;
124 cout << "Section name " << sec_name << ":" << endl;
125 for (auto it = duration_list.begin(); it != duration_list.end(); ++it) {
126 long duration_since_begin_start =
127 chrono::duration_cast<chrono::milliseconds>(*it - ProcessTimer::begin).count();
128
129 long duration_since_begin_end =
130 chrono::duration_cast<chrono::milliseconds>(*std::next(it) - ProcessTimer::begin).count();
131
132 cout << "Duration " << i << ": " << duration_since_begin_start << "ms-->" << duration_since_begin_end << "ms"
133 << endl;
134 i++;
135 }
136 }
137}
138
140{
141 json j;
142 j["metadata"] = metadata;
143 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json." + to_string(times_written),
144 ios::app);
145 list<long> durations_since_begin;
146
147 ProcessTimer::duration_map_t::key_type sec_name;
148 ProcessTimer::duration_map_t::mapped_type duration_list;
149 for (auto const &durations_element : ProcessTimer::durations) {
150 std::tie(sec_name, duration_list) = std::move(durations_element);
151 durations_since_begin.clear();
152 for (auto const &timestamp : duration_list) {
153 durations_since_begin.push_back(
154 chrono::duration_cast<chrono::microseconds>(timestamp - ProcessTimer::begin).count());
155 }
156 j[sec_name] = durations_since_begin;
157 }
158 file << std::setw(4) << j;
159 file.close();
160}
161
163{
164 if (write_interval) {
165 json j, meta;
166 meta.push_back(std::move(data));
167 j["metadata"] = meta;
168 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json", ios::app);
169 file << std::setw(4) << j;
170 } else {
171 metadata.push_back(std::move(data));
172 }
173}
174
176{
177 write_interval = write_int;
178 if (write_interval) {
179 json j, meta;
180 meta["write_interval"] = true;
181 j["metadata"] = meta;
182 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json", ios::app);
183 file << std::setw(4) << j;
184 }
185}
186
187// Initialize static members
189chrono::time_point<chrono::steady_clock> ProcessTimer::begin = chrono::steady_clock::now();
190chrono::time_point<chrono::steady_clock> ProcessTimer::previous_write = chrono::steady_clock::now();
191pid_t ProcessTimer::process = 0;
195
196} // namespace MultiProcess
197} // namespace RooFit
nlohmann::json json
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
static void add_metadata(json data)
static void set_write_interval(int write_interval)
static void print_durations(std::string to_print="all")
static std::chrono::time_point< std::chrono::steady_clock > begin
static std::list< std::chrono::time_point< std::chrono::steady_clock > > get_durations(std::string section_name)
static std::chrono::time_point< std::chrono::steady_clock > previous_write
static void start_timer(std::string section_name)
std::map< std::string, std::list< std::chrono::time_point< std::chrono::steady_clock > > > duration_map_t
static duration_map_t durations
static void end_timer(std::string section_name)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition JSONIO.h:26
Definition file.py:1