GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
event_log.hpp
1 /*
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
24 #ifndef EVENT_LOG_HPP
25 #define EVENT_LOG_HPP
26 #include <iostream>
27 #include <boost/bind.hpp>
28 #include <graphlab/parallel/pthread_tools.hpp>
29 #include <graphlab/parallel/atomic.hpp>
30 #include <graphlab/util/timer.hpp>
31 #include <graphlab/util/dense_bitset.hpp>
32 namespace graphlab {
33 
34 #define EVENT_MAX_COUNTERS 256
35 
36 class event_log{
37  public:
38  enum event_print_type{
39  NUMBER,
40  DESCRIPTION,
41  RATE_BAR,
42  LOG_FILE
43  };
44  private:
45  std::ostream* out; // output target
46  volatile size_t flush_interval; // flush frequency (ms)
47  event_print_type print_method; // print method
48  volatile bool finished; // set on destruction
49 
50  mutex m;
51  conditional cond;
52 
53  thread printing_thread;
54  std::string descriptions[EVENT_MAX_COUNTERS];
55  size_t maxcounter[EVENT_MAX_COUNTERS];
56  atomic<size_t> counters[EVENT_MAX_COUNTERS];
57  atomic<size_t> totalcounter[EVENT_MAX_COUNTERS];
58 
59  std::vector<std::pair<unsigned char, size_t> > immediate_events;
60 
61  double prevtime; // last time flush() was called
62  bool hasevents; // whether there are logging events
63  size_t noeventctr; // how many times flush() was called with no events
64  // zeroed when the events are next observed.
65 
66  size_t max_desc_length; // maximum descriptor length
67  fixed_dense_bitset<EVENT_MAX_COUNTERS> hascounter;
68  public:
69  inline event_log():out(NULL),
70  flush_interval(0),
71  print_method(DESCRIPTION),
72  finished(false),
73  prevtime(0),
74  hasevents(false),
75  noeventctr(0),
76  max_desc_length(0) {
77  hascounter.clear();
78  for (size_t i = 0;i < EVENT_MAX_COUNTERS; ++i) {
79  maxcounter[i] = 0;
80  totalcounter[i].value = 0;
81  }
82  printing_thread.launch(boost::bind(&event_log::thread_loop, this));
83  }
84 
85  void initialize(std::ostream &ostrm,
86  size_t flush_interval_ms,
87  event_print_type event_print);
88 
89  void close();
90 
91  void thread_loop();
92 
93  void add_event_type(unsigned char eventid, std::string description);
94  void add_immediate_event_type(unsigned char eventid, std::string description);
95 
96  inline void accumulate_event(unsigned char eventid,
97  size_t count) __attribute__((always_inline)) {
98  hasevents = true;
99  counters[eventid].inc(count);
100  totalcounter[eventid].inc(count);
101  }
102 
103  void immediate_event(unsigned char eventid);
104 
105  void flush();
106 
107  ~event_log();
108 };
109 
110 }
111 /**
112  * DECLARE_EVENT_LOG(name)
113  * creates an event log with a given name. This creates a variable
114  * called "name" which is of type event_log. and is equivalent to:
115  *
116  * graphlab::event_log name;
117  *
118  * The primary reason to use this macro instead of just writing
119  * the code above directly, is that the macro is ignored and compiles
120  * to nothing when event logs are disabled.
121  *
122  *
123  * INITIALIZE_EVENT_LOG(name, ostrm, flush_interval, printdesc)
124  * ostrm is the output std::ostream object. A pointer of the stream
125  * is taken so the stream should not be destroyed until the event log is closed
126  * flush_interval is the flush frequency in milliseconds.
127  * printdesc is either graphlab::event_log::NUMBER, or graphlab::event_log::DESCRIPTION or
128  * graphlab::event_log::RATE_BAR. There is also graphlab::event_log::LOG_FILE
129  * which outputs to a centralized log. If this is used, the ostrm argument
130  * is ignored and an output of the DESCRIPTION format will be written to an
131  * eventlog.txt file in the current directory.
132  *
133  * ADD_EVENT_TYPE(name, id, desc)
134  * Creates an event type with an integer ID, and a description.
135  * Event types should be mostly consecutive since the internal
136  * storage format is a array. Valid ID range is [0, 255]
137  *
138  * ACCUMULATE_EVENT(name, id, count)
139  * Adds 'count' events of type "id"
140  *
141  * FLUSH_EVENT_LOG(name)
142  * Forces a flush of the accumulated events to the provided output stream
143  */
144 #ifdef USE_EVENT_LOG
145 #define DECLARE_EVENT_LOG(name) graphlab::event_log name;
146 #define INITIALIZE_EVENT_LOG(name, ostrm, flush_interval, printdesc) \
147  name.initialize(ostrm, flush_interval, printdesc);
148 #define ADD_EVENT_TYPE(name, id, desc) name.add_event_type(id, desc);
149 #define ADD_IMMEDIATE_EVENT_TYPE(name, id, desc) name.add_immediate_event_type(id, desc);
150 #define ACCUMULATE_EVENT(name, id, count) name.accumulate_event(id, count);
151 #define IMMEDIATE_EVENT(name, id) name.immediate_event(id);
152 #define FLUSH_EVENT_LOG(name) name.flush();
153 #define CLOSE_EVENT_LOG(name) name.close();
154 
155 #else
156 #define DECLARE_EVENT_LOG(name)
157 #define INITIALIZE_EVENT_LOG(name, ostrm, flush_interval, printdesc)
158 #define ADD_EVENT_TYPE(name, id, desc)
159 #define ADD_IMMEDIATE_EVENT_TYPE(name, id, desc)
160 #define ACCUMULATE_EVENT(name, id, count)
161 #define IMMEDIATE_EVENT(name, id)
162 #define FLUSH_EVENT_LOG(name)
163 #define CLOSE_EVENT_LOG(name)
164 #endif
165 
166 #define PERMANENT_DECLARE_EVENT_LOG(name) graphlab::event_log name;
167 #define PERMANENT_INITIALIZE_EVENT_LOG(name, ostrm, flush_interval, printdesc) \
168  name.initialize(ostrm, flush_interval, printdesc);
169 #define PERMANENT_ADD_EVENT_TYPE(name, id, desc) name.add_event_type(id, desc);
170 #define PERMANENT_ADD_IMMEDIATE_EVENT_TYPE(name, id, desc) name.add_immediate_event_type(id, desc);
171 #define PERMANENT_ACCUMULATE_EVENT(name, id, count) name.accumulate_event(id, count);
172 #define PERMANENT_IMMEDIATE_EVENT(name, id) name.immediate_event(id);
173 #define PERMANENT_FLUSH_EVENT_LOG(name) name.flush();
174 #define PERMANENT_CLOSE_EVENT_LOG(name) name.close();
175 
176 
177 #endif