1 /* Copyright (c) 2008-2010, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 // This file is part of ThreadSanitizer, a dynamic data race detector. 28 // Author: Konstantin Serebryany. 29 // Author: Timur Iskhodzhanov. 30 #ifndef TS_STATS_ 31 #define TS_STATS_ 32 33 #include "dynamic_annotations.h" 34 #include "ts_util.h" 35 36 // Statistic counters for each thread. 37 // For stats accessed concurrently from different threads 38 // we don't want to use global stats to avoid cache line ping-pong. 39 struct ThreadLocalStats { 40 ThreadLocalStats() { Clear(); } 41 void Clear() { 42 memset(this, 0, sizeof(*this)); 43 } 44 uintptr_t memory_access_sizes[18]; 45 uintptr_t events[LAST_EVENT]; 46 uintptr_t unlocked_access_ok; 47 uintptr_t n_fast_access1, n_fast_access2, n_fast_access4, n_fast_access8, 48 n_slow_access1, n_slow_access2, n_slow_access4, n_slow_access8, 49 n_very_slow_access, n_access_slow_iter; 50 51 uintptr_t mops_per_trace[16]; 52 uintptr_t locks_per_trace[16]; 53 uintptr_t locked_access[8]; 54 uintptr_t history_uses_same_segment, history_creates_new_segment, 55 history_reuses_segment, history_uses_preallocated_segment; 56 57 uintptr_t msm_branch_count[16]; 58 59 uintptr_t access_to_first_1g; 60 uintptr_t access_to_first_2g; 61 uintptr_t access_to_first_4g; 62 63 uintptr_t cache_fast_get; 64 }; 65 66 // Statistic counters for the entire tool, including aggregated 67 // ThreadLocalStats (which are made private so that one can not 68 // increment them using the global stats object). 69 struct Stats : private ThreadLocalStats { 70 Stats() { 71 memset(this, 0, sizeof(*this)); 72 ANNOTATE_BENIGN_RACE(&vts_clone, "Race on vts_clone"); 73 ANNOTATE_BENIGN_RACE(&ignore_below_cache_miss, 74 "Race on ignore_below_cache_miss"); 75 ANNOTATE_BENIGN_RACE_SIZED(msm_branch_count, sizeof(msm_branch_count), 76 "Race on msm_branch_count[]"); 77 } 78 79 void Add(const ThreadLocalStats &s) { 80 uintptr_t *p1 = (uintptr_t*)this; 81 uintptr_t *p2 = (uintptr_t*)&s; 82 size_t n = sizeof(s) / sizeof(uintptr_t); 83 for (size_t i = 0; i < n; i++) { 84 p1[i] += p2[i]; 85 } 86 } 87 88 void PrintStats() { 89 PrintEventStats(); 90 Printf(" VTS: created small/big: %'ld / %'ld; " 91 "deleted small/big: %'ld / %'ld; cloned: %'ld\n", 92 vts_create_small, vts_create_big, 93 vts_delete_small, vts_delete_big, vts_clone); 94 Printf(" vts_total_create = %'ld; avg=%'ld; delete = %'ld\n", 95 vts_total_create, 96 vts_total_create / (vts_create_small + vts_create_big + 1), 97 vts_total_delete); 98 Printf(" n_seg_hb = %'ld\n", n_seg_hb); 99 Printf(" n_vts_hb = %'ld\n", n_vts_hb); 100 Printf(" n_vts_hb_cached = %'ld\n", n_vts_hb_cached); 101 Printf(" memory access:\n" 102 " 1: %'ld / %'ld\n" 103 " 2: %'ld / %'ld\n" 104 " 4: %'ld / %'ld\n" 105 " 8: %'ld / %'ld\n" 106 " s: %'ld\n", 107 n_fast_access1, n_slow_access1, 108 n_fast_access2, n_slow_access2, 109 n_fast_access4, n_slow_access4, 110 n_fast_access8, n_slow_access8, 111 n_very_slow_access); 112 PrintStatsForCache(); 113 // Printf(" Mops:\n" 114 // " total = %'ld\n" 115 // " unique = %'ld\n", 116 // mops_total, mops_uniq); 117 Printf(" Publish: set: %'ld; get: %'ld; clear: %'ld\n", 118 publish_set, publish_get, publish_clear); 119 120 Printf(" PcTo: all: %'ld\n", pc_to_strings); 121 122 Printf(" StackTrace: create: %'ld; delete %'ld\n", 123 stack_trace_create, stack_trace_delete); 124 125 Printf(" History segments: same: %'ld; reuse: %'ld; " 126 "preallocated: %'ld; new: %'ld\n", 127 history_uses_same_segment, history_reuses_segment, 128 history_uses_preallocated_segment, history_creates_new_segment); 129 Printf(" Forget all history: %'ld\n", n_forgets); 130 131 PrintStatsForSeg(); 132 PrintStatsForSS(); 133 PrintStatsForLS(); 134 } 135 136 void PrintStatsForSS() { 137 Printf(" SegmentSet: created: %'ld; reused: %'ld;" 138 " find: %'ld; recycle: %'ld\n", 139 ss_create, ss_reuse, ss_find, ss_recycle); 140 Printf(" sizes: 2: %'ld; 3: %'ld; 4: %'ld; other: %'ld\n", 141 ss_size_2, ss_size_3, ss_size_4, ss_size_other); 142 143 // SSEq is called at least (ss_find + ss_recycle) times since 144 // FindExistingOrAlocateAndCopy calls map_.find() 145 // and RecycleOneSegmentSet calls map_.erase(it) 146 // Both find() and erase(it) require at least one call to SSHash and SSEq. 147 // 148 // Apart from SSHash call locations mentioned above, 149 // SSHash is called for each AllocateAndCopy (ss_create + ss_reuse) times 150 // for insert() AFTER it has already been called 151 // by FindExistingOrAlocateAndCopy in case find() returned map_.end(). 152 // Hence the factor of 2. 153 uintptr_t sseq_estimated = ss_find + ss_recycle, 154 sshash_estimated = sseq_estimated + 2 * (ss_create + ss_reuse); 155 Printf(" SSHash called %12ld times (vs. %12ld = +%d%%)\n" 156 " SSEq called %12ld times (vs. %12ld = +%d%%)\n", 157 sshash_calls, sshash_estimated, 158 (sshash_calls - sshash_estimated)/(sshash_estimated/100 + 1), 159 sseq_calls, sseq_estimated, 160 (sseq_calls - sseq_estimated )/(sseq_estimated/100 + 1)); 161 } 162 void PrintStatsForCache() { 163 Printf(" Cache:\n" 164 " fast = %'ld\n" 165 " new = %'ld\n" 166 " delete = %'ld\n" 167 " fetch = %'ld\n" 168 " storage = %'ld\n", 169 cache_fast_get, cache_new_line, 170 cache_delete_empty_line, cache_fetch, 171 cache_max_storage_size); 172 } 173 174 void PrintStatsForSeg() { 175 Printf(" Segment: created: %'ld; reused: %'ld\n", 176 seg_create, seg_reuse); 177 } 178 179 void PrintStatsForLS() { 180 Printf(" LockSet add: 0: %'ld; 1 : %'ld; n : %'ld\n", 181 ls_add_to_empty, ls_add_to_singleton, ls_add_to_multi); 182 Printf(" LockSet rem: 1: %'ld; n : %'ld\n", 183 ls_remove_from_singleton, ls_remove_from_multi); 184 Printf(" LockSet cache: add : %'ld; rem : %'ld; fast: %'ld\n", 185 ls_add_cache_hit, ls_rem_cache_hit, ls_cache_fast); 186 Printf(" LockSet size: 2: %'ld 3: %'ld 4: %'ld 5: %'ld other: %'ld\n", 187 ls_size_2, ls_size_3, ls_size_4, ls_size_5, ls_size_other); 188 } 189 190 void PrintEventStats() { 191 uintptr_t total = 0; 192 for (int i = 0; i < LAST_EVENT; i++) { 193 if (events[i]) { 194 Printf(" %25s: %'ld\n", Event::TypeString((EventType)i), 195 events[i]); 196 } 197 total += events[i]; 198 } 199 Printf(" %25s: %'ld\n", "Total", total); 200 for (size_t i = 0; i < TS_ARRAY_SIZE(memory_access_sizes); i++) { 201 if (memory_access_sizes[i]) { 202 Printf(" mop[%d]: %'ld\n", i, memory_access_sizes[i]); 203 } 204 } 205 for (size_t i = 0; i < TS_ARRAY_SIZE(mops_per_trace); i++) { 206 Printf(" mops_per_trace[%d] = %'ld\n", i, mops_per_trace[i]); 207 } 208 for (size_t i = 0; i < TS_ARRAY_SIZE(locks_per_trace); i++) { 209 Printf(" locks_per_trace[%d] = %'ld\n", i, locks_per_trace[i]); 210 } 211 212 uintptr_t total_locks = 0; 213 for (size_t i = 0; i < TS_ARRAY_SIZE(lock_sites); i++) { 214 if(lock_sites[i] == 0) continue; 215 Printf("lock_sites[%ld]=%ld\n", i, lock_sites[i]); 216 total_locks += lock_sites[i]; 217 } 218 Printf("lock_sites[*]=%ld\n", total_locks); 219 Printf("futex_wait =%ld\n", futex_wait); 220 Printf("unlocked_access_ok =%'ld\n", unlocked_access_ok); 221 uintptr_t all_locked_access = 0; 222 for (size_t i = 0; i < TS_ARRAY_SIZE(locked_access); i++) { 223 uintptr_t t = locked_access[i]; 224 if (t) Printf("locked_access[%ld] =%'ld\n", i, t); 225 all_locked_access += t; 226 } 227 Printf("locked_access[*] =%'ld\n", all_locked_access); 228 Printf("try_acquire_line_spin =%ld\n", try_acquire_line_spin); 229 Printf("access to first 1/2/4 G: %'ld %'ld %'ld\n", 230 access_to_first_1g, access_to_first_2g, access_to_first_4g); 231 232 233 for (size_t i = 0; i < TS_ARRAY_SIZE(tleb_flush); i++) { 234 if(tleb_flush[i] == 0) continue; 235 Printf("tleb_flush[%ld]=%ld\n", i, tleb_flush[i]); 236 } 237 Printf("IgnoreBelowCache miss=%ld\n", ignore_below_cache_miss); 238 for (size_t i = 0; i < TS_ARRAY_SIZE(msm_branch_count); i++) { 239 if (msm_branch_count[i]) 240 Printf("msm_branch_count[%02d] = %'ld\n", i, msm_branch_count[i]); 241 } 242 if (read_proc_self_stats) 243 Printf("read_proc_self_stats =%ld\n", read_proc_self_stats); 244 } 245 246 247 248 uintptr_t n_vts_hb; 249 uintptr_t n_vts_hb_cached; 250 uintptr_t n_seg_hb; 251 252 uintptr_t ls_add_to_empty, ls_add_to_singleton, ls_add_to_multi, 253 ls_remove_from_singleton, ls_remove_from_multi, 254 ls_add_cache_hit, ls_rem_cache_hit, 255 ls_cache_fast, 256 ls_size_2, ls_size_3, ls_size_4, ls_size_5, ls_size_other; 257 258 uintptr_t cache_new_line; 259 uintptr_t cache_delete_empty_line; 260 uintptr_t cache_fetch; 261 uintptr_t cache_max_storage_size; 262 263 uintptr_t mops_total; 264 uintptr_t mops_uniq; 265 266 uintptr_t vts_create_big, vts_create_small, 267 vts_clone, vts_delete_small, vts_delete_big, 268 vts_total_delete, vts_total_create; 269 270 uintptr_t ss_create, ss_reuse, ss_find, ss_recycle; 271 uintptr_t ss_size_2, ss_size_3, ss_size_4, ss_size_other; 272 273 uintptr_t sshash_calls, sseq_calls; 274 275 uintptr_t seg_create, seg_reuse; 276 277 uintptr_t publish_set, publish_get, publish_clear; 278 279 uintptr_t pc_to_strings; 280 281 uintptr_t stack_trace_create, stack_trace_delete; 282 283 uintptr_t n_forgets; 284 285 uintptr_t lock_sites[20]; 286 287 uintptr_t tleb_flush[10]; 288 289 uintptr_t ignore_below_cache_miss; 290 291 uintptr_t try_acquire_line_spin; 292 uintptr_t futex_wait; 293 uintptr_t read_proc_self_stats; 294 }; 295 296 297 // end. {{{1 298 #endif // TS_STATS_ 299 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80 300