HPCToolkit
datacentric.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2017, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 
48 /******************************************************************************
49  * system includes
50  *****************************************************************************/
51 
52 #include <stdlib.h>
53 #include <stddef.h>
54 #include <string.h>
55 #include <assert.h>
56 #include <unistd.h>
57 #include <sys/mman.h>
58 #include <stdbool.h>
59 
60 #include <linux/perf_event.h> // perf_mem_data_src
61 
62 /******************************************************************************
63  * libmonitor
64  *****************************************************************************/
65 
66 #include <monitor.h>
67 
68 
69 
70 /******************************************************************************
71  * local includes
72  *****************************************************************************/
73 
74 #include <hpcrun/disabled.h>
75 #include <hpcrun/metrics.h>
76 #include <sample_event.h>
77 #include <main.h>
78 #include <loadmap.h>
79 #include <hpcrun/thread_data.h>
80 
81 #include <messages/messages.h>
82 
83 #include <cct/cct_bundle.h>
84 #include <cct/cct.h>
85 #include <cct/cct_addr.h> // struct var_addr_s
86 
87 #include "include/queue.h" // linked-list
88 
89 #include "datacentric.h"
90 #include "data-overrides.h"
91 #include "data_tree.h"
92 #include "env.h"
93 
95 
96 
97 /******************************************************************************
98  * macros
99  *****************************************************************************/
100 
101 
102 /******************************************************************************
103  * prototypes and forward declaration
104  *****************************************************************************/
105 
106 
107 /******************************************************************************
108  * data structure
109  *****************************************************************************/
110 
111 
112 
113 /******************************************************************************
114  * Place forlder
115  *****************************************************************************/
116 //
117 // "Special" routine to serve as a placeholder for "dynamic" allocation
118 //
119 
120 static void
122 {}
123 
124 //
125 // "Special" routine to serve as a placeholder for "static" global variables
126 //
127 
128 static void
130 {}
131 
132 //
133 // "Special" routine to serve as a placeholder for any variables that
134 // are not static nor dynamic
135 //
136 static void
138 {}
139 
140 /******************************************************************************
141  * PRIVATE Function implementation
142  *****************************************************************************/
143 
144 
145 
146 static cct_node_t*
148  uintptr_t addr_start, uintptr_t addr_end)
149 {
150  // create a node for this variable
151 
152  ip_normalized_t npc;
154 
155  memset(&npc, 0, sizeof(ip_normalized_t));
156  memset(&addr, 0, sizeof(cct_addr_t));
157 
158  // create a node with the ip = memory address
159  // this node will be translated by hpcprof and name it with
160  // the static variable that matches with the memory address
161 
162  npc.lm_ip = addr_start + 1; // hpcprof sometimes decrements the value of IP.
163  npc.lm_id = lm_id;
164  addr.ip_norm = npc;
165 
166  cct_node_t *context = hpcrun_cct_insert_addr(root, &addr);
167 
168  // assign the start address and the end address metric
169  // for this node
170  int metric_id = datacentric_get_metric_addr_start();
171  metric_set_t *mset = hpcrun_reify_metric_set(context);
172 
173  hpcrun_metricVal_t value;
174  value.p = (void*)addr_start;
175  hpcrun_metric_std_min(metric_id, mset, value);
176 
177  metric_id = datacentric_get_metric_addr_end();
178  value.p = (void*)addr_end;
179  hpcrun_metric_std_max(metric_id, mset, value);
180 
181  return context;
182 }
183 
184 
185 
186 /***
187  * manage signal handler for datacentric event
188  */
189 static void
191 {
192  if ( (args->current == NULL) || (args->data == NULL) ||
193  (args->sample->sample_node == NULL))
194  return;
195 
196  perf_mmap_data_t *mmap_data = args->data;
197 
198  cct_node_t *sample_node = args->sample->sample_node;
199  cct_node_t *node = sample_node;
200 
201  // ---------------------------------------------------------
202  // memory information exists:
203  // - check if we have this variable address in our database
204  // - if it's in our database (either static or dynamic), add it to the cct node
205  // - otherwise, it must be unknown variable. Not sure what we should do with this
206  // ---------------------------------------------------------
207  if (mmap_data->addr) {
208 
209  // --------------------------------------------------------------
210  // store the memory address reported by the hardware counter to the metric
211  // even if the address is outside the range of recognized variable (see
212  // datatree_splay_lookup() function which returns if the address is recognized)
213  // we may need to keep the information (?).
214  // another solution is to create a sibling node to avoid to step over the
215  // recognized metric.
216  // --------------------------------------------------------------
217 
218  void *start = NULL, *end = NULL;
219 
220  datatree_info_t *info = datatree_splay_lookup((void*) mmap_data->addr, &start, &end);
221  cct_node_t *var_context = NULL;
224 
225  // --------------------------------------------------------------
226  // try to find the accessed memory address from the database
227  // if the accessed memory is within the range (found in the database), then it must be
228  // either static variable or heap allocation
229  // otherwise, we encounter an unknown variable
230  // --------------------------------------------------------------
231 
232  if (info) {
233  var_context = info->context;
234 
235  if (info->magic == DATA_STATIC_MAGIC) {
236  // attach this node of static variable to the datacentric root
237 
238  cct_node_t *datacentric_root = hpcrun_cct_bundle_init_datacentric_node(bundle);
239  cct_node_t *variable_root = hpcrun_insert_special_node(datacentric_root, DATACENTRIC_Static);
240  cct_addr_t *addr = hpcrun_cct_addr(sample_node);
241 
242  var_context = datacentric_create_root_node(variable_root, addr->ip_norm.lm_id,
243  (uintptr_t)info->memblock, (uintptr_t)info->rmemblock);
244 
245  // mark that this is a special node for global variable
246  // hpcprof will treat specially to print the name of the variable to xml file
247  // (if hpcstruct provides the information)
248 
249  hpcrun_cct_set_node_variable(var_context);
250 
251  } else {
252  // dynamic allocation
253  cct_node_t *datacentric_root = hpcrun_cct_bundle_init_datacentric_node(bundle);
254  cct_node_t *variable_root = hpcrun_insert_special_node(datacentric_root, DATACENTRIC_Dynamic);
255 
256  var_context = hpcrun_cct_insert_path_return_leaf(var_context, variable_root);
257 
258  hpcrun_cct_set_node_allocation(var_context);
259  }
260  } else {
261  // unknown variable
262  cct_node_t *datacentric_root = hpcrun_cct_bundle_init_datacentric_node(bundle);
263  var_context = hpcrun_insert_special_node(datacentric_root, DATACENTRIC_Unknown);
264 
265  hpcrun_cct_set_node_variable(var_context);
266  }
267 
268  // copy the callpath of the sample to the variable context
269  node = hpcrun_cct_insert_path_return_leaf(sample_node, var_context);
270 
272 
273  // variable address is store in the database
274  // record the interval of this access
275 
276  hpcrun_metricVal_t val_addr;
277  val_addr.p = (void *)mmap_data->addr;
278 
279  // check if this is the minimum value. if this is the case, record it in the metric
280  int metric_id = datacentric_get_metric_addr_start();
281  hpcrun_metric_std_min(metric_id, mset, val_addr);
282 
283  // check if this is the maximum value. if this is the case, record it in the metric
284  metric_id = datacentric_get_metric_addr_end();
285  val_addr.p++;
286  hpcrun_metric_std_max(metric_id, mset, val_addr);
287 
288  // re-record metric event for this node
289  hpcrun_metric_std_inc(args->metric, mset, (hpcrun_metricVal_t) {.r=args->metric_value});
290 
292  }
293 
294  // hardware specific event handler
295  datacentric_hw_handler(mmap_data, node, sample_node);
296 }
297 
298 
299 
300 /****
301  * register datacentric event
302  * the method is designed to be called by the main thread or at least by one thread,
303  * during initialization of the process (before creation of OpenMP threads).
304  *
305  * This method will create metrics for different memory events and then the
306  * metrics are read-only, it will not modified by others.
307  * All children threads will use this metrics to record the memory activities.
308  */
309 static int
311  event_custom_t *event,
312  struct event_threshold_s *period)
313 {
314  struct event_threshold_s threshold;
315  perf_util_get_default_threshold( &threshold );
316 
317  // ------------------------------------------
318  // hardware-specific data centric setup (if supported)
319  // ------------------------------------------
320  int result = datacentric_hw_register(self, event, &threshold);
321  if (result == 0)
322  return 0;
323 
324  return 1;
325 }
326 
327 
328 /******************************************************************************
329  * PUBLIC method definitions
330  *****************************************************************************/
331 
332 void
334 {
335  event_custom_t *event_datacentric = hpcrun_malloc(sizeof(event_custom_t));
336  event_datacentric->name = EVNAME_DATACENTRIC;
337  event_datacentric->desc = "Experimental counter: counting the memory latency.";
338  event_datacentric->register_fn = datacentric_register; // call backs
339  event_datacentric->handler_fn = datacentric_handler;
340  event_datacentric->handle_type = EXCLUSIVE;// call me only for my events
341 
342  event_custom_register(event_datacentric);
343 }
struct event_info_s * current
Definition: event_custom.h:64
void * memblock
Definition: data_tree.h:70
metric_set_t * hpcrun_reify_metric_set(cct_node_id_t cct_id)
Definition: cct2metrics.c:115
static cct_node_t * datacentric_create_root_node(cct_node_t *root, uint16_t lm_id, uintptr_t addr_start, uintptr_t addr_end)
Definition: datacentric.c:147
int datacentric_get_metric_addr_end()
static void DATACENTRIC_Dynamic(void)
Definition: datacentric.c:121
static int datacentric_register(sample_source_t *self, event_custom_t *event, struct event_threshold_s *period)
Definition: datacentric.c:310
cct_node_t * node
Definition: cct.c:128
void datacentric_init()
Definition: datacentric.c:333
event_handler_t * handler_fn
Definition: event_custom.h:89
cct_node_t * sample_node
Definition: sample_event.h:96
void datacentric_hw_handler(perf_mmap_data_t *mmap_data, cct_node_t *datacentric_node, cct_node_t *sample_node)
Definition: ibsop.c:63
void hpcrun_metric_std_min(int metric_id, metric_set_t *set, hpcrun_metricVal_t val)
Definition: metrics.c:542
static void DATACENTRIC_Unknown(void)
Definition: datacentric.c:137
uintptr_t lm_ip
Definition: ip-normalized.h:78
cct_bundle_t csdata
Definition: epoch.h:65
cct_node_t * hpcrun_cct_insert_addr(cct_node_t *node, cct_addr_t *frm)
Definition: cct.c:405
void hpcrun_metric_std_max(int metric_id, metric_set_t *set, hpcrun_metricVal_t val)
Definition: metrics.c:549
static void datacentric_handler(event_handler_arg_t *args)
Definition: datacentric.c:190
cct_node_t * hpcrun_insert_special_node(cct_node_t *root, void *addr)
Definition: cct.c:861
#define EVNAME_DATACENTRIC
Definition: env.h:92
int datacentric_hw_register(sample_source_t *self, event_custom_t *event, struct event_threshold_s *period)
Definition: ibsop.c:70
void perf_util_get_default_threshold(struct event_threshold_s *threshold)
Definition: perf-util.c:347
core_profile_trace_data_t core_profile_trace_data
Definition: thread_data.h:168
struct perf_mmap_data_s * data
Definition: event_custom.h:65
ip_normalized_t ip_norm
Definition: cct_addr.h:66
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
cct_node_t * context
Definition: data_tree.h:68
const char * desc
Definition: event_custom.h:86
int datacentric_get_metric_addr_start()
void hpcrun_cct_set_node_variable(cct_node_t *node)
Definition: cct.c:480
cct_node_t * hpcrun_cct_bundle_init_datacentric_node(cct_bundle_t *cct)
Definition: cct_bundle.c:170
#define DATA_STATIC_MAGIC
Definition: data_tree.h:57
register_event_t * register_fn
Definition: event_custom.h:88
#define NULL
Definition: ElfHelper.cpp:85
cct_node_t * hpcrun_cct_insert_path_return_leaf(cct_node_t *path, cct_node_t *root)
Definition: cct.c:871
Definition: cct.c:96
struct datatree_info_s * datatree_splay_lookup(void *key, void **start, void **end)
Definition: data_tree.c:203
event_handle_type_t handle_type
Definition: event_custom.h:91
static void DATACENTRIC_Static(void)
Definition: datacentric.c:129
cct_addr_t * addr
Definition: cct.c:130
void hpcrun_cct_set_node_memaccess(cct_node_t *node)
Definition: cct.c:495
void hpcrun_cct_set_node_allocation(cct_node_t *node)
Definition: cct.c:468
void * rmemblock
Definition: data_tree.h:71
const char * name
Definition: event_custom.h:85
void hpcrun_metric_std_inc(int metric_id, metric_set_t *set, hpcrun_metricVal_t incr)
Definition: metrics.c:534
static long period
Definition: itimer.c:194
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
int event_custom_register(event_custom_t *event)
Definition: event_custom.c:110
sample_val_t * sample
Definition: event_custom.h:62
cct_addr_t * hpcrun_cct_addr(cct_node_t *node)
Definition: cct.c:369