OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/stats_table.h" | 5 #include "base/stats_table.h" |
6 | 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/platform_thread.h" |
| 9 #include "base/shared_memory.h" |
7 #include "base/string_util.h" | 10 #include "base/string_util.h" |
8 #include "base/logging.h" | |
9 #include "base/thread_local_storage.h" | 11 #include "base/thread_local_storage.h" |
10 #include "base/platform_thread.h" | |
11 | 12 |
12 #if defined(OS_POSIX) | 13 #if defined(OS_POSIX) |
13 #include "errno.h" | 14 #include "errno.h" |
14 #endif | 15 #endif |
15 | 16 |
16 // The StatsTable uses a shared memory segment that is laid out as follows | 17 // The StatsTable uses a shared memory segment that is laid out as follows |
17 // | 18 // |
18 // +-------------------------------------------+ | 19 // +-------------------------------------------+ |
19 // | Version | Size | MaxCounters | MaxThreads | | 20 // | Version | Size | MaxCounters | MaxThreads | |
20 // +-------------------------------------------+ | 21 // +-------------------------------------------+ |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 class StatsTablePrivate { | 109 class StatsTablePrivate { |
109 public: | 110 public: |
110 // Various header information contained in the memory mapped segment. | 111 // Various header information contained in the memory mapped segment. |
111 struct TableHeader { | 112 struct TableHeader { |
112 int version; | 113 int version; |
113 int size; | 114 int size; |
114 int max_counters; | 115 int max_counters; |
115 int max_threads; | 116 int max_threads; |
116 }; | 117 }; |
117 | 118 |
118 // Create the StatsTablePrivate based on expected size parameters. | 119 // Construct a new StatsTablePrivate based on expected size parameters, or |
119 StatsTablePrivate(void* memory, int size, int max_threads, int max_counters); | 120 // return NULL on failure. |
| 121 static StatsTablePrivate* New(const std::wstring& name, int size, |
| 122 int max_threads, int max_counters); |
| 123 |
| 124 SharedMemory* shared_memory() { return &shared_memory_; } |
120 | 125 |
121 // Accessors for our header pointers | 126 // Accessors for our header pointers |
122 TableHeader* table_header() const { return table_header_; } | 127 TableHeader* table_header() const { return table_header_; } |
123 int version() const { return table_header_->version; } | 128 int version() const { return table_header_->version; } |
124 int size() const { return table_header_->size; } | 129 int size() const { return table_header_->size; } |
125 int max_counters() const { return table_header_->max_counters; } | 130 int max_counters() const { return table_header_->max_counters; } |
126 int max_threads() const { return table_header_->max_threads; } | 131 int max_threads() const { return table_header_->max_threads; } |
127 | 132 |
128 // Accessors for our tables | 133 // Accessors for our tables |
129 wchar_t* thread_name(int slot_id) const { | 134 wchar_t* thread_name(int slot_id) const { |
130 return &thread_names_table_[ | 135 return &thread_names_table_[ |
131 (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; | 136 (slot_id-1) * (StatsTable::kMaxThreadNameLength)]; |
132 } | 137 } |
133 int* thread_tid(int slot_id) const { | 138 int* thread_tid(int slot_id) const { |
134 return &(thread_tid_table_[slot_id-1]); | 139 return &(thread_tid_table_[slot_id-1]); |
135 } | 140 } |
136 int* thread_pid(int slot_id) const { | 141 int* thread_pid(int slot_id) const { |
137 return &(thread_pid_table_[slot_id-1]); | 142 return &(thread_pid_table_[slot_id-1]); |
138 } | 143 } |
139 wchar_t* counter_name(int counter_id) const { | 144 wchar_t* counter_name(int counter_id) const { |
140 return &counter_names_table_[ | 145 return &counter_names_table_[ |
141 (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; | 146 (counter_id-1) * (StatsTable::kMaxCounterNameLength)]; |
142 } | 147 } |
143 int* row(int counter_id) const { | 148 int* row(int counter_id) const { |
144 return &data_table_[(counter_id-1) * max_threads()]; | 149 return &data_table_[(counter_id-1) * max_threads()]; |
145 } | 150 } |
146 | 151 |
147 private: | 152 private: |
| 153 // Constructor is private because you should use New() instead. |
| 154 StatsTablePrivate() {} |
| 155 |
148 // Initializes the table on first access. Sets header values | 156 // Initializes the table on first access. Sets header values |
149 // appropriately and zeroes all counters. | 157 // appropriately and zeroes all counters. |
150 void InitializeTable(void* memory, int size, int max_counters, | 158 void InitializeTable(void* memory, int size, int max_counters, |
151 int max_threads); | 159 int max_threads); |
152 | 160 |
153 // Initializes our in-memory pointers into a pre-created StatsTable. | 161 // Initializes our in-memory pointers into a pre-created StatsTable. |
154 void ComputeMappedPointers(void* memory); | 162 void ComputeMappedPointers(void* memory); |
155 | 163 |
| 164 SharedMemory shared_memory_; |
156 TableHeader* table_header_; | 165 TableHeader* table_header_; |
157 wchar_t* thread_names_table_; | 166 wchar_t* thread_names_table_; |
158 int* thread_tid_table_; | 167 int* thread_tid_table_; |
159 int* thread_pid_table_; | 168 int* thread_pid_table_; |
160 wchar_t* counter_names_table_; | 169 wchar_t* counter_names_table_; |
161 int* data_table_; | 170 int* data_table_; |
162 }; | 171 }; |
163 | 172 |
164 StatsTablePrivate::StatsTablePrivate(void* memory, int size, int max_threads, | 173 // static |
165 int max_counters) { | 174 StatsTablePrivate* StatsTablePrivate::New(const std::wstring& name, |
| 175 int size, |
| 176 int max_threads, |
| 177 int max_counters) { |
| 178 scoped_ptr<StatsTablePrivate> priv(new StatsTablePrivate()); |
| 179 |
| 180 if (!priv->shared_memory_.Create(name, false, true, size)) |
| 181 return NULL; |
| 182 if (!priv->shared_memory_.Map(size)) |
| 183 return NULL; |
| 184 void* memory = priv->shared_memory_.memory(); |
| 185 |
166 TableHeader* header = static_cast<TableHeader*>(memory); | 186 TableHeader* header = static_cast<TableHeader*>(memory); |
| 187 |
167 // If the version does not match, then assume the table needs | 188 // If the version does not match, then assume the table needs |
168 // to be initialized. | 189 // to be initialized. |
169 if (header->version != kTableVersion) | 190 if (header->version != kTableVersion) |
170 InitializeTable(memory, size, max_counters, max_threads); | 191 priv->InitializeTable(memory, size, max_counters, max_threads); |
171 | 192 |
172 // We have a valid table, so compute our pointers. | 193 // We have a valid table, so compute our pointers. |
173 ComputeMappedPointers(memory); | 194 priv->ComputeMappedPointers(memory); |
| 195 |
| 196 return priv.release(); |
174 } | 197 } |
175 | 198 |
176 void StatsTablePrivate::InitializeTable(void* memory, int size, | 199 void StatsTablePrivate::InitializeTable(void* memory, int size, |
177 int max_counters, | 200 int max_counters, |
178 int max_threads) { | 201 int max_threads) { |
179 // Zero everything. | 202 // Zero everything. |
180 memset(memory, 0, size); | 203 memset(memory, 0, size); |
181 | 204 |
182 // Initialize the header. | 205 // Initialize the header. |
183 TableHeader* header = static_cast<TableHeader*>(memory); | 206 TableHeader* header = static_cast<TableHeader*>(memory); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 DCHECK_EQ(offset, size()); | 245 DCHECK_EQ(offset, size()); |
223 } | 246 } |
224 | 247 |
225 | 248 |
226 | 249 |
227 // We keep a singleton table which can be easily accessed. | 250 // We keep a singleton table which can be easily accessed. |
228 StatsTable* StatsTable::global_table_ = NULL; | 251 StatsTable* StatsTable::global_table_ = NULL; |
229 | 252 |
230 StatsTable::StatsTable(const std::wstring& name, int max_threads, | 253 StatsTable::StatsTable(const std::wstring& name, int max_threads, |
231 int max_counters) | 254 int max_counters) |
232 : tls_index_(SlotReturnFunction) { | 255 : impl_(NULL), |
| 256 tls_index_(SlotReturnFunction) { |
233 int table_size = | 257 int table_size = |
234 AlignedSize(sizeof(StatsTablePrivate::TableHeader)) + | 258 AlignedSize(sizeof(StatsTablePrivate::TableHeader)) + |
235 AlignedSize((max_counters * sizeof(wchar_t) * kMaxCounterNameLength)) + | 259 AlignedSize((max_counters * sizeof(wchar_t) * kMaxCounterNameLength)) + |
236 AlignedSize((max_threads * sizeof(wchar_t) * kMaxThreadNameLength)) + | 260 AlignedSize((max_threads * sizeof(wchar_t) * kMaxThreadNameLength)) + |
237 AlignedSize(max_threads * sizeof(int)) + | 261 AlignedSize(max_threads * sizeof(int)) + |
238 AlignedSize(max_threads * sizeof(int)) + | 262 AlignedSize(max_threads * sizeof(int)) + |
239 AlignedSize((sizeof(int) * (max_counters * max_threads))); | 263 AlignedSize((sizeof(int) * (max_counters * max_threads))); |
240 | 264 |
241 impl_ = NULL; | 265 impl_ = StatsTablePrivate::New(name, table_size, max_threads, max_counters); |
242 // TODO(mbelshe): Move this out of the constructor | 266 |
243 if (shared_memory_.Create(name, false, true, table_size)) | 267 // TODO(port): clean up this error reporting. |
244 if (shared_memory_.Map(table_size)) | |
245 impl_ = new StatsTablePrivate(shared_memory_.memory(), table_size, | |
246 max_threads, max_counters); | |
247 #if defined(OS_WIN) | 268 #if defined(OS_WIN) |
248 if (!impl_) | 269 if (!impl_) |
249 LOG(ERROR) << "StatsTable did not initialize:" << GetLastError(); | 270 LOG(ERROR) << "StatsTable did not initialize:" << GetLastError(); |
250 #elif defined(OS_POSIX) | 271 #elif defined(OS_POSIX) |
251 if (!impl_) | 272 if (!impl_) |
252 LOG(ERROR) << "StatsTable did not initialize:" << strerror(errno); | 273 LOG(ERROR) << "StatsTable did not initialize:" << strerror(errno); |
253 #endif | 274 #endif |
254 } | 275 } |
255 | 276 |
256 StatsTable::~StatsTable() { | 277 StatsTable::~StatsTable() { |
(...skipping 13 matching lines...) Expand all Loading... |
270 global_table_ = NULL; | 291 global_table_ = NULL; |
271 } | 292 } |
272 | 293 |
273 int StatsTable::RegisterThread(const std::wstring& name) { | 294 int StatsTable::RegisterThread(const std::wstring& name) { |
274 int slot = 0; | 295 int slot = 0; |
275 | 296 |
276 // Registering a thread requires that we lock the shared memory | 297 // Registering a thread requires that we lock the shared memory |
277 // so that two threads don't grab the same slot. Fortunately, | 298 // so that two threads don't grab the same slot. Fortunately, |
278 // thread creation shouldn't happen in inner loops. | 299 // thread creation shouldn't happen in inner loops. |
279 { | 300 { |
280 SharedMemoryAutoLock lock(&shared_memory_); | 301 SharedMemoryAutoLock lock(impl_->shared_memory()); |
281 slot = FindEmptyThread(); | 302 slot = FindEmptyThread(); |
282 if (!slot) { | 303 if (!slot) { |
283 return 0; | 304 return 0; |
284 } | 305 } |
285 | 306 |
286 DCHECK(impl_); | 307 DCHECK(impl_); |
287 | 308 |
288 // We have space, so consume a column in the table. | 309 // We have space, so consume a column in the table. |
289 std::wstring thread_name = name; | 310 std::wstring thread_name = name; |
290 if (name.empty()) | 311 if (name.empty()) |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 int StatsTable::AddCounter(const std::wstring& name) { | 447 int StatsTable::AddCounter(const std::wstring& name) { |
427 DCHECK(impl_); | 448 DCHECK(impl_); |
428 | 449 |
429 if (!impl_) | 450 if (!impl_) |
430 return 0; | 451 return 0; |
431 | 452 |
432 int counter_id = 0; | 453 int counter_id = 0; |
433 { | 454 { |
434 // To add a counter to the shared memory, we need the | 455 // To add a counter to the shared memory, we need the |
435 // shared memory lock. | 456 // shared memory lock. |
436 SharedMemoryAutoLock lock(&shared_memory_); | 457 SharedMemoryAutoLock lock(impl_->shared_memory()); |
437 | 458 |
438 // We have space, so create a new counter. | 459 // We have space, so create a new counter. |
439 counter_id = FindCounterOrEmptyRow(name); | 460 counter_id = FindCounterOrEmptyRow(name); |
440 if (!counter_id) | 461 if (!counter_id) |
441 return 0; | 462 return 0; |
442 | 463 |
443 std::wstring counter_name = name; | 464 std::wstring counter_name = name; |
444 if (name.empty()) | 465 if (name.empty()) |
445 counter_name = kUnknownName; | 466 counter_name = kUnknownName; |
446 base::wcslcpy(impl_->counter_name(counter_id), counter_name.c_str(), | 467 base::wcslcpy(impl_->counter_name(counter_id), counter_name.c_str(), |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
528 return NULL; | 549 return NULL; |
529 | 550 |
530 // Find the counter id for the counter. | 551 // Find the counter id for the counter. |
531 std::wstring str_name(name); | 552 std::wstring str_name(name); |
532 int counter = table->FindCounter(str_name); | 553 int counter = table->FindCounter(str_name); |
533 | 554 |
534 // Now we can find the location in the table. | 555 // Now we can find the location in the table. |
535 return table->GetLocation(counter, slot); | 556 return table->GetLocation(counter, slot); |
536 } | 557 } |
537 | 558 |
OLD | NEW |