HPCToolkit
blame-map.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-2019, 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 // directed blame shifting for locks, critical sections, ...
49 //
50 
51 /******************************************************************************
52  * system includes
53  *****************************************************************************/
54 
55 #include <assert.h>
56 
57 
58 
59 /******************************************************************************
60  * local includes
61  *****************************************************************************/
62 
63 #include "blame-map.h"
64 
67 #include <memory/hpcrun-malloc.h>
68 
69 /******************************************************************************
70  * macros
71  *****************************************************************************/
72 
73 #define N (128*1024)
74 #define INDEX_MASK ((N)-1)
75 
76 #define LOSSLESS_BLAME
77 
78 #ifdef BLAME_MAP_LOCKING
79 
80 #define do_lock() \
81 { \
82  for(;;) { \
83  if (fetch_and_store_i64(&thelock, 1) == 0) break; \
84  while (thelock == 1); \
85  } \
86 }
87 
88 #define do_unlock() thelock = 0
89 
90 #else
91 
92 #define do_lock()
93 #define do_unlock()
94 
95 #endif
96 
97 
98 
99 /******************************************************************************
100  * data type
101  *****************************************************************************/
102 
103 typedef struct {
104  uint32_t obj_id;
105  uint32_t blame;
106 } blame_parts_t;
107 
108 
110  atomic_uint_least64_t all;
112 };
113 
114 
115 
116 /***************************************************************************
117  * private data
118  ***************************************************************************/
119 
120 static uint64_t volatile thelock;
121 
122 
123 
124 /***************************************************************************
125  * private operations
126  ***************************************************************************/
127 
128 uint32_t
129 blame_map_obj_id(uint64_t obj)
130 {
131  return ((uint32_t) ((uint64_t)obj) >> 2);
132 }
133 
134 
135 uint32_t
136 blame_map_hash(uint64_t obj)
137 {
138  return ((uint32_t)((blame_map_obj_id(obj)) & INDEX_MASK));
139 }
140 
141 
142 uint64_t
143 blame_map_entry(uint64_t obj, uint32_t metric_value)
144 {
145  blame_entry_t be;
146  be.parts.obj_id = blame_map_obj_id(obj);
147  be.parts.blame = metric_value;
149 }
150 
151 
152 
153 /***************************************************************************
154  * interface operations
155  ***************************************************************************/
156 
159 {
160  blame_entry_t* rv = hpcrun_malloc(N * sizeof(blame_entry_t));
161  blame_map_init(rv);
162  return rv;
163 }
164 
165 void
167 {
168  int i;
169  for(i = 0; i < N; i++) {
170  table[i].parts.obj_id = 0;
171  table[i].parts.blame = 0;
172  }
173 }
174 
175 
176 void
178  uint64_t obj, uint32_t metric_value)
179 {
180  uint32_t obj_id = blame_map_obj_id(obj);
181  uint32_t index = blame_map_hash(obj);
182 
183  assert(index >= 0 && index < N);
184 
185  do_lock();
186  for(;;) {
187  blame_entry_t oldval = table[index];
188 
189  if(oldval.parts.obj_id == obj_id) {
190 #ifdef LOSSLESS_BLAME
191  blame_entry_t newval = oldval;
192  newval.parts.blame += metric_value;
193  uint64_t oldall = atomic_load_explicit(&oldval.all, memory_order_relaxed);
194  uint64_t testoldall = oldall;
195  uint64_t newall = atomic_load_explicit(&oldval.all, memory_order_relaxed);
196  if (atomic_compare_exchange_strong_explicit(&table[index].all, &oldall, newall,
198  == testoldall) break;
199 #else
200  oldval.parts.blame += metric_value;
201  table[index].all = oldval.all;
202  break;
203 #endif
204  } else {
205  if(oldval.parts.obj_id == 0) {
206  uint64_t newval = blame_map_entry(obj, metric_value);
207 #ifdef LOSSLESS_BLAME
208  uint64_t oldall = atomic_load_explicit(&oldval.all, memory_order_relaxed);
209  uint64_t testoldall = oldall;
210  if ((atomic_compare_exchange_strong_explicit(&table[index].all, &oldall, newval,
212  == testoldall) break;
213  // otherwise, try again
214 #else
215  table[index].all = newval;
216  break;
217 #endif
218  }
219  else {
220  EMSG("leaked blame %d\n", metric_value);
221  // entry in use for another object's blame
222  // in this case, since it isn't easy to shift
223  // our blame efficiently, we simply drop it.
224  break;
225  }
226  }
227  }
228  do_unlock();
229 }
230 
231 
232 uint64_t
233 blame_map_get_blame(blame_entry_t table[], uint64_t obj)
234 {
235  static uint64_t zero = 0;
236  uint64_t val = 0;
237  uint32_t obj_id = blame_map_obj_id(obj);
238  uint32_t index = blame_map_hash(obj);
239 
240  assert(index >= 0 && index < N);
241 
242  do_lock();
243  for(;;) {
244  blame_entry_t oldval = table[index];
245  if(oldval.parts.obj_id == obj_id) {
246 #ifdef LOSSLESS_BLAME
247  uint64_t oldall = atomic_load_explicit(&oldval.all, memory_order_relaxed);
248  uint64_t testoldall = oldall;
249  if (atomic_compare_exchange_strong_explicit(&table[index].all, &oldall, zero,
251  != testoldall) continue; // try again on failure
252 #else
253  table[index].all = 0;
254 #endif
255  val = (uint64_t)oldval.parts.blame;
256  }
257  break;
258  }
259  do_unlock();
260 
261  return val;
262 }
#define N
Definition: blame-map.c:73
blame_parts_t parts
Definition: blame-map.c:111
uint32_t obj_id
Definition: blame-map.c:104
#define INDEX_MASK
Definition: blame-map.c:74
#define do_lock()
Definition: blame-map.c:92
#define atomic_load_explicit(object, order)
Definition: stdatomic.h:378
void blame_map_init(blame_entry_t table[])
Definition: blame-map.c:166
uint64_t blame_map_entry(uint64_t obj, uint32_t metric_value)
Definition: blame-map.c:143
static uint64_t volatile thelock
Definition: blame-map.c:120
Definition: blame-map.c:109
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure)
Definition: stdatomic.h:335
uint64_t blame_map_get_blame(blame_entry_t table[], uint64_t obj)
Definition: blame-map.c:233
#define EMSG
Definition: messages.h:70
uint32_t blame_map_obj_id(uint64_t obj)
Definition: blame-map.c:129
void blame_map_add_blame(blame_entry_t table[], uint64_t obj, uint32_t metric_value)
Definition: blame-map.c:177
atomic_uint_least64_t all
Definition: blame-map.c:110
#define do_unlock()
Definition: blame-map.c:93
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
uint32_t blame_map_hash(uint64_t obj)
Definition: blame-map.c:136
blame_entry_t * blame_map_new(void)
Definition: blame-map.c:158
uint32_t blame
Definition: blame-map.c:105