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) = durations_element;
43 if (sec_name != to_return) {
44 continue;
45 } else {
46 return duration_list;
47 }
48 }
49 throw ::invalid_argument("section name " + to_return +
50 " not found in timer map, so it cannot"
51 " be retrieved");
52}
53
54void ProcessTimer::start_timer(string section_name)
55{
56 auto it = ProcessTimer::durations.find(section_name);
57 if (it == ProcessTimer::durations.end()) {
58 // Key does not exist in map yet, start the first timer of this section
59 ProcessTimer::durations.insert({section_name, {chrono::steady_clock::now()}});
60 } else if (it->second.size() % 2 != 0) {
61 // All even indices contain start times, if size of list is currently even we can not start a new timer
62 throw ::invalid_argument("Section name " + section_name +
63 " timer has already started, and was not stopped before calling `start_timer`");
64 } else {
65 // Add start time to list
66 it->second.push_back(chrono::steady_clock::now());
67 }
68}
69
70void ProcessTimer::end_timer(string section_name)
71{
72 auto it = ProcessTimer::durations.find(section_name);
73 if (it == ProcessTimer::durations.end()) {
74 // Key does not exist in map yet
75 throw ::invalid_argument("Section name " + section_name + " timer was never started!");
76 } else if (it->second.size() % 2 == 0) {
77 // All odd indices contain end times, if size of list is currently odd we can not start a new timer
78 throw ::invalid_argument("Section name " + section_name +
79 " timer does exist, but was not started before calling `end_timer`");
80 } else {
81 // Add end time to list
82 it->second.push_back(chrono::steady_clock::now());
83 }
84
85 // Write to file intermittently if interval is reached and write_interval is set
86 if (write_interval && (chrono::duration_cast<chrono::seconds>(chrono::steady_clock::now() - previous_write).count() >
88 previous_write = chrono::steady_clock::now();
91 }
92}
93
94void ProcessTimer::print_durations(string to_print)
95{
96 cout << "On PID: " << ProcessTimer::process << endl << "====================" << endl << endl;
97 ProcessTimer::duration_map_t::key_type sec_name;
98 ProcessTimer::duration_map_t::mapped_type duration_list;
99 for (auto const &durations_element : ProcessTimer::durations) {
100 std::tie(sec_name, duration_list) = durations_element;
101 if (to_print != "all" && sec_name != to_print)
102 continue; // continue if only asked for specific section
103
104 int i = 0;
105 long total_duration = 0;
106 cout << "Section name " << sec_name << ":" << endl;
107 for (auto it = duration_list.begin(); it != duration_list.end(); ++it) {
108 long duration = chrono::duration_cast<chrono::milliseconds>(*std::next(it) - *it).count();
109 cout << "Duration " << i << ": " << duration << "ms +" << endl;
110 total_duration += duration;
111 i++;
112 }
113 cout << "--------------------" << endl << "Total: " << total_duration << "ms" << endl << endl;
114 }
115}
116
118{
119 cout << "On PID: " << ProcessTimer::process << endl;
120 ProcessTimer::duration_map_t::key_type sec_name;
121 ProcessTimer::duration_map_t::mapped_type duration_list;
122 for (auto const &durations_element : ProcessTimer::durations) {
123 std::tie(sec_name, duration_list) = durations_element;
124 int i = 0;
125 cout << "Section name " << sec_name << ":" << endl;
126 for (auto it = duration_list.begin(); it != duration_list.end(); ++it) {
127 long duration_since_begin_start =
128 chrono::duration_cast<chrono::milliseconds>(*it - ProcessTimer::begin).count();
129
130 long duration_since_begin_end =
131 chrono::duration_cast<chrono::milliseconds>(*std::next(it) - ProcessTimer::begin).count();
132
133 cout << "Duration " << i << ": " << duration_since_begin_start << "ms-->" << duration_since_begin_end << "ms"
134 << endl;
135 i++;
136 }
137 }
138}
139
141{
142 json j;
143 j["metadata"] = metadata;
144 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json." + to_string(times_written),
145 ios::app);
146 list<long> durations_since_begin;
147
148 ProcessTimer::duration_map_t::key_type sec_name;
149 ProcessTimer::duration_map_t::mapped_type duration_list;
150 for (auto const &durations_element : ProcessTimer::durations) {
151 std::tie(sec_name, duration_list) = durations_element;
152 durations_since_begin.clear();
153 for (auto const &timestamp : duration_list) {
154 durations_since_begin.push_back(
155 chrono::duration_cast<chrono::microseconds>(timestamp - ProcessTimer::begin).count());
156 }
157 j[sec_name] = durations_since_begin;
158 }
159 file << std::setw(4) << j;
160 file.close();
161}
162
164{
165 if (write_interval) {
166 json j;
167 json meta;
168 meta.push_back(std::move(data));
169 j["metadata"] = meta;
170 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json", ios::app);
171 file << std::setw(4) << j;
172 } else {
173 metadata.push_back(std::move(data));
174 }
175}
176
178{
179 write_interval = write_int;
180 if (write_interval) {
181 json j;
182 json meta;
183 meta["write_interval"] = true;
184 j["metadata"] = meta;
185 std::ofstream file("p_" + to_string((long)ProcessTimer::get_process()) + ".json", ios::app);
186 file << std::setw(4) << j;
187 }
188}
189
190// Initialize static members
192chrono::time_point<chrono::steady_clock> ProcessTimer::begin = chrono::steady_clock::now();
193chrono::time_point<chrono::steady_clock> ProcessTimer::previous_write = chrono::steady_clock::now();
194pid_t ProcessTimer::process = 0;
198
199} // namespace MultiProcess
200} // 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