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 // Histogram is an object that aggregates statistics, and can summarize them in | 5 // Histogram is an object that aggregates statistics, and can summarize them in |
6 // various forms, including ASCII graphical, HTML, and numerically (as a | 6 // various forms, including ASCII graphical, HTML, and numerically (as a |
7 // vector of numbers corresponding to each of the aggregating buckets). | 7 // vector of numbers corresponding to each of the aggregating buckets). |
8 | 8 |
9 // It supports calls to accumulate either time intervals (which are processed | 9 // It supports calls to accumulate either time intervals (which are processed |
10 // as integral number of milliseconds), or arbitrary integral units. | 10 // as integral number of milliseconds), or arbitrary integral units. |
(...skipping 18 matching lines...) Expand all Loading... |
29 // gigantic range with the addition of very few buckets. | 29 // gigantic range with the addition of very few buckets. |
30 | 30 |
31 #ifndef BASE_HISTOGRAM_H__ | 31 #ifndef BASE_HISTOGRAM_H__ |
32 #define BASE_HISTOGRAM_H__ | 32 #define BASE_HISTOGRAM_H__ |
33 | 33 |
34 #include <map> | 34 #include <map> |
35 #include <string> | 35 #include <string> |
36 #include <vector> | 36 #include <vector> |
37 | 37 |
38 #include "base/lock.h" | 38 #include "base/lock.h" |
| 39 #include "base/pickle.h" |
39 #include "base/scoped_ptr.h" | 40 #include "base/scoped_ptr.h" |
40 #include "base/stats_counters.h" | 41 #include "base/stats_counters.h" |
41 | 42 |
42 //------------------------------------------------------------------------------ | 43 //------------------------------------------------------------------------------ |
43 // Provide easy general purpose histogram in a macro, just like stats counters. | 44 // Provide easy general purpose histogram in a macro, just like stats counters. |
44 // The first two macros use 50 buckets. | 45 // The first two macros use 50 buckets. |
45 | 46 |
46 #define HISTOGRAM_TIMES(name, sample) do { \ | 47 #define HISTOGRAM_TIMES(name, sample) do { \ |
47 static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ | 48 static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ |
48 base::TimeDelta::FromSeconds(10), 50); \ | 49 base::TimeDelta::FromSeconds(10), 50); \ |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
111 #endif // NDEBUG | 112 #endif // NDEBUG |
112 | 113 |
113 //------------------------------------------------------------------------------ | 114 //------------------------------------------------------------------------------ |
114 // The following macros provide typical usage scenarios for callers that wish | 115 // The following macros provide typical usage scenarios for callers that wish |
115 // to record histogram data, and have the data submitted/uploaded via UMA. | 116 // to record histogram data, and have the data submitted/uploaded via UMA. |
116 // Not all systems support such UMA, but if they do, the following macros | 117 // Not all systems support such UMA, but if they do, the following macros |
117 // should work with the service. | 118 // should work with the service. |
118 | 119 |
119 static const int kUmaTargetedHistogramFlag = 0x1; | 120 static const int kUmaTargetedHistogramFlag = 0x1; |
120 | 121 |
| 122 // This indicates the histogram is shadow copy of renderer histrogram |
| 123 // constructed by unpick method and updated regularly from renderer upload |
| 124 // of histograms. |
| 125 static const int kRendererHistogramFlag = 1 << 4; |
| 126 |
121 #define UMA_HISTOGRAM_TIMES(name, sample) do { \ | 127 #define UMA_HISTOGRAM_TIMES(name, sample) do { \ |
122 static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ | 128 static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ |
123 base::TimeDelta::FromSeconds(10), 50); \ | 129 base::TimeDelta::FromSeconds(10), 50); \ |
124 counter.SetFlags(kUmaTargetedHistogramFlag); \ | 130 counter.SetFlags(kUmaTargetedHistogramFlag); \ |
125 counter.AddTime(sample); \ | 131 counter.AddTime(sample); \ |
126 } while (0) | 132 } while (0) |
127 | 133 |
128 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) do { \ | 134 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) do { \ |
129 static Histogram counter((name), base::TimeDelta::FromMilliseconds(10), \ | 135 static Histogram counter((name), base::TimeDelta::FromMilliseconds(10), \ |
130 base::TimeDelta::FromMinutes(3), 50); \ | 136 base::TimeDelta::FromMinutes(3), 50); \ |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
176 public: | 182 public: |
177 typedef int Sample; // Used for samples (and ranges of samples). | 183 typedef int Sample; // Used for samples (and ranges of samples). |
178 typedef int Count; // Used to count samples in a bucket. | 184 typedef int Count; // Used to count samples in a bucket. |
179 static const Sample kSampleType_MAX = INT_MAX; | 185 static const Sample kSampleType_MAX = INT_MAX; |
180 | 186 |
181 typedef std::vector<Count> Counts; | 187 typedef std::vector<Count> Counts; |
182 typedef std::vector<Sample> Ranges; | 188 typedef std::vector<Sample> Ranges; |
183 | 189 |
184 static const int kHexRangePrintingFlag; | 190 static const int kHexRangePrintingFlag; |
185 | 191 |
| 192 enum BucketLayout { |
| 193 EXPONENTIAL, |
| 194 LINEAR |
| 195 }; |
| 196 |
186 //---------------------------------------------------------------------------- | 197 //---------------------------------------------------------------------------- |
187 // Statistic values, developed over the life of the histogram. | 198 // Statistic values, developed over the life of the histogram. |
188 | 199 |
189 class SampleSet { | 200 class SampleSet { |
190 public: | 201 public: |
191 explicit SampleSet(); | 202 explicit SampleSet(); |
192 // Adjust size of counts_ for use with given histogram. | 203 // Adjust size of counts_ for use with given histogram. |
193 void Resize(const Histogram& histogram); | 204 void Resize(const Histogram& histogram); |
194 void CheckSize(const Histogram& histogram) const; | 205 void CheckSize(const Histogram& histogram) const; |
195 | 206 |
196 // Accessor for histogram to make routine additions. | 207 // Accessor for histogram to make routine additions. |
197 void Accumulate(Sample value, Count count, size_t index); | 208 void Accumulate(Sample value, Count count, size_t index); |
198 | 209 |
199 // Accessor methods. | 210 // Accessor methods. |
200 Count counts(size_t i) const { return counts_[i]; } | 211 Count counts(size_t i) const { return counts_[i]; } |
201 Count TotalCount() const; | 212 Count TotalCount() const; |
202 int64 sum() const { return sum_; } | 213 int64 sum() const { return sum_; } |
203 int64 square_sum() const { return square_sum_; } | 214 int64 square_sum() const { return square_sum_; } |
204 | 215 |
205 // Arithmetic manipulation of corresponding elements of the set. | 216 // Arithmetic manipulation of corresponding elements of the set. |
206 void Add(const SampleSet& other); | 217 void Add(const SampleSet& other); |
207 void Subtract(const SampleSet& other); | 218 void Subtract(const SampleSet& other); |
208 | 219 |
| 220 bool Serialize(Pickle* pickle) const; |
| 221 bool Deserialize(void** iter, const Pickle& pickle); |
| 222 |
209 protected: | 223 protected: |
210 // Actual histogram data is stored in buckets, showing the count of values | 224 // Actual histogram data is stored in buckets, showing the count of values |
211 // that fit into each bucket. | 225 // that fit into each bucket. |
212 Counts counts_; | 226 Counts counts_; |
213 | 227 |
214 // Save simple stats locally. Note that this MIGHT get done in base class | 228 // Save simple stats locally. Note that this MIGHT get done in base class |
215 // without shared memory at some point. | 229 // without shared memory at some point. |
216 int64 sum_; // sum of samples. | 230 int64 sum_; // sum of samples. |
217 int64 square_sum_; // sum of squares of samples. | 231 int64 square_sum_; // sum of squares of samples. |
218 }; | 232 }; |
219 //---------------------------------------------------------------------------- | 233 //---------------------------------------------------------------------------- |
220 | 234 |
221 Histogram(const char* name, Sample minimum, | 235 Histogram(const char* name, Sample minimum, |
222 Sample maximum, size_t bucket_count); | 236 Sample maximum, size_t bucket_count); |
223 Histogram(const char* name, base::TimeDelta minimum, | 237 Histogram(const char* name, base::TimeDelta minimum, |
224 base::TimeDelta maximum, size_t bucket_count); | 238 base::TimeDelta maximum, size_t bucket_count); |
225 virtual ~Histogram(); | 239 virtual ~Histogram(); |
226 | 240 |
227 // Hooks to override stats counter methods. This ensures that we gather all | 241 // Hooks to override stats counter methods. This ensures that we gather all |
228 // input the stats counter sees. | 242 // input the stats counter sees. |
229 virtual void Add(int value); | 243 virtual void Add(int value); |
230 | 244 |
| 245 void AddSampleSet(const SampleSet& sample); |
| 246 |
231 // The following methods provide graphical histogram displays. | 247 // The following methods provide graphical histogram displays. |
232 void WriteHTMLGraph(std::string* output) const; | 248 void WriteHTMLGraph(std::string* output) const; |
233 void WriteAscii(bool graph_it, const std::string& newline, | 249 void WriteAscii(bool graph_it, const std::string& newline, |
234 std::string* output) const; | 250 std::string* output) const; |
235 | 251 |
236 // Support generic flagging of Histograms. | 252 // Support generic flagging of Histograms. |
237 // 0x1 Currently used to mark this histogram to be recorded by UMA.. | 253 // 0x1 Currently used to mark this histogram to be recorded by UMA.. |
238 // 0x8000 means print ranges in hex. | 254 // 0x8000 means print ranges in hex. |
239 void SetFlags(int flags) { flags_ |= flags; } | 255 void SetFlags(int flags) { flags_ |= flags; } |
240 void ClearFlags(int flags) { flags_ &= ~flags; } | 256 void ClearFlags(int flags) { flags_ &= ~flags; } |
241 int flags() const { return flags_; } | 257 int flags() const { return flags_; } |
242 | 258 |
| 259 virtual BucketLayout histogram_type() const { return EXPONENTIAL; } |
| 260 |
| 261 // Convenience methods for serializing/deserializing the histograms. |
| 262 // Histograms from Renderer process are serialized and sent to the browser. |
| 263 // Browser process reconstructs the histogram from the pickled version |
| 264 // accumulates the browser-side shadow copy of histograms (that mirror |
| 265 // histograms created in the renderer). |
| 266 |
| 267 // Serialize the given snapshot of a Histogram into a String. Uses |
| 268 // Pickle class to flatten the object. |
| 269 static std::string SerializeHistogramInfo(const Histogram& histogram, |
| 270 const SampleSet& snapshot); |
| 271 // The following method accepts a list of pickled histograms and |
| 272 // builds a histogram and updates shadow copy of histogram data in the |
| 273 // browser process. |
| 274 static void DeserializeHistogramList( |
| 275 const std::vector<std::string>& histograms); |
| 276 static bool DeserializeHistogramInfo(const std::string& state); |
| 277 |
| 278 |
243 //---------------------------------------------------------------------------- | 279 //---------------------------------------------------------------------------- |
244 // Accessors for serialization and testing. | 280 // Accessors for serialization and testing. |
245 //---------------------------------------------------------------------------- | 281 //---------------------------------------------------------------------------- |
246 const std::string histogram_name() const { return histogram_name_; } | 282 const std::string histogram_name() const { return histogram_name_; } |
247 Sample declared_min() const { return declared_min_; } | 283 Sample declared_min() const { return declared_min_; } |
248 Sample declared_max() const { return declared_max_; } | 284 Sample declared_max() const { return declared_max_; } |
249 virtual Sample ranges(size_t i) const { return ranges_[i];} | 285 virtual Sample ranges(size_t i) const { return ranges_[i];} |
250 virtual size_t bucket_count() const { return bucket_count_; } | 286 virtual size_t bucket_count() const { return bucket_count_; } |
251 // Snapshot the current complete set of sample data. | 287 // Snapshot the current complete set of sample data. |
252 // Override with atomic/locked snapshot if needed. | 288 // Override with atomic/locked snapshot if needed. |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 // The dimension of ranges_ is bucket_count + 1. | 373 // The dimension of ranges_ is bucket_count + 1. |
338 Ranges ranges_; | 374 Ranges ranges_; |
339 | 375 |
340 // Finally, provide the state that changes with the addition of each new | 376 // Finally, provide the state that changes with the addition of each new |
341 // sample. | 377 // sample. |
342 SampleSet sample_; | 378 SampleSet sample_; |
343 | 379 |
344 // Indicate if successfully registered. | 380 // Indicate if successfully registered. |
345 bool registered_; | 381 bool registered_; |
346 | 382 |
347 DISALLOW_EVIL_CONSTRUCTORS(Histogram); | 383 DISALLOW_COPY_AND_ASSIGN(Histogram); |
348 }; | 384 }; |
349 | 385 |
350 //------------------------------------------------------------------------------ | 386 //------------------------------------------------------------------------------ |
351 | 387 |
352 // LinearHistogram is a more traditional histogram, with evenly spaced | 388 // LinearHistogram is a more traditional histogram, with evenly spaced |
353 // buckets. | 389 // buckets. |
354 class LinearHistogram : public Histogram { | 390 class LinearHistogram : public Histogram { |
355 public: | 391 public: |
356 struct DescriptionPair { | 392 struct DescriptionPair { |
357 Sample sample; | 393 Sample sample; |
358 const char* description; // Null means end of a list of pairs. | 394 const char* description; // Null means end of a list of pairs. |
359 }; | 395 }; |
360 LinearHistogram(const char* name, Sample minimum, | 396 LinearHistogram(const char* name, Sample minimum, |
361 Sample maximum, size_t bucket_count); | 397 Sample maximum, size_t bucket_count); |
| 398 |
362 LinearHistogram(const char* name, base::TimeDelta minimum, | 399 LinearHistogram(const char* name, base::TimeDelta minimum, |
363 base::TimeDelta maximum, size_t bucket_count); | 400 base::TimeDelta maximum, size_t bucket_count); |
364 ~LinearHistogram() {} | 401 ~LinearHistogram() {} |
365 | 402 |
366 // Store a list of number/text values for use in rendering the histogram. | 403 // Store a list of number/text values for use in rendering the histogram. |
367 // The last element in the array has a null in its "description" slot. | 404 // The last element in the array has a null in its "description" slot. |
368 void SetRangeDescriptions(const DescriptionPair descriptions[]); | 405 void SetRangeDescriptions(const DescriptionPair descriptions[]); |
369 | 406 |
| 407 virtual BucketLayout histogram_type() const { return LINEAR; } |
| 408 |
370 protected: | 409 protected: |
371 // Initialize ranges_ mapping. | 410 // Initialize ranges_ mapping. |
372 virtual void InitializeBucketRange(); | 411 virtual void InitializeBucketRange(); |
373 // Find bucket to increment for sample value. | 412 // Find bucket to increment for sample value. |
374 virtual size_t BucketIndex(Sample value) const; | 413 virtual size_t BucketIndex(Sample value) const; |
375 virtual double GetBucketSize(Count current, size_t i) const; | 414 virtual double GetBucketSize(Count current, size_t i) const; |
376 | 415 |
377 // If we have a description for a bucket, then return that. Otherwise | 416 // If we have a description for a bucket, then return that. Otherwise |
378 // let parent class provide a (numeric) description. | 417 // let parent class provide a (numeric) description. |
379 virtual const std::string GetAsciiBucketRange(size_t i) const; | 418 virtual const std::string GetAsciiBucketRange(size_t i) const; |
380 | 419 |
381 // Skip printing of name for numeric range if we have a name (and if this is | 420 // Skip printing of name for numeric range if we have a name (and if this is |
382 // an empty bucket). | 421 // an empty bucket). |
383 virtual bool PrintEmptyBucket(size_t index) const; | 422 virtual bool PrintEmptyBucket(size_t index) const; |
384 | 423 |
385 private: | 424 private: |
386 // For some ranges, we store a printable description of a bucket range. | 425 // For some ranges, we store a printable description of a bucket range. |
387 // If there is no desciption, then GetAsciiBucketRange() uses parent class | 426 // If there is no desciption, then GetAsciiBucketRange() uses parent class |
388 // to provide a description. | 427 // to provide a description. |
389 typedef std::map<Sample, std::string> BucketDescriptionMap; | 428 typedef std::map<Sample, std::string> BucketDescriptionMap; |
390 BucketDescriptionMap bucket_description_; | 429 BucketDescriptionMap bucket_description_; |
391 | 430 |
392 DISALLOW_EVIL_CONSTRUCTORS(LinearHistogram); | 431 DISALLOW_COPY_AND_ASSIGN(LinearHistogram); |
393 }; | 432 }; |
394 | 433 |
395 //------------------------------------------------------------------------------ | 434 //------------------------------------------------------------------------------ |
396 | 435 |
397 // BooleanHistogram is a histogram for booleans. | 436 // BooleanHistogram is a histogram for booleans. |
398 class BooleanHistogram : public LinearHistogram { | 437 class BooleanHistogram : public LinearHistogram { |
399 public: | 438 public: |
400 explicit BooleanHistogram(const char* name) | 439 explicit BooleanHistogram(const char* name) |
401 : LinearHistogram(name, 0, 2, 3) { | 440 : LinearHistogram(name, 0, 2, 3) { |
402 } | 441 } |
403 | 442 |
404 virtual void AddBoolean(bool value) { Add(value ? 1 : 0); } | 443 virtual void AddBoolean(bool value) { Add(value ? 1 : 0); } |
405 | 444 |
406 private: | 445 private: |
407 DISALLOW_EVIL_CONSTRUCTORS(BooleanHistogram); | 446 DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); |
408 }; | 447 }; |
409 | 448 |
410 //------------------------------------------------------------------------------ | 449 //------------------------------------------------------------------------------ |
411 // This section provides implementation for ThreadSafeHistogram. | 450 // This section provides implementation for ThreadSafeHistogram. |
412 //------------------------------------------------------------------------------ | 451 //------------------------------------------------------------------------------ |
413 | 452 |
414 class ThreadSafeHistogram : public Histogram { | 453 class ThreadSafeHistogram : public Histogram { |
415 public: | 454 public: |
416 ThreadSafeHistogram(const char* name, Sample minimum, | 455 ThreadSafeHistogram(const char* name, Sample minimum, |
417 Sample maximum, size_t bucket_count); | 456 Sample maximum, size_t bucket_count); |
418 | 457 |
419 // Provide the analog to Add() | 458 // Provide the analog to Add() |
420 void Remove(int value); | 459 void Remove(int value); |
421 | 460 |
422 protected: | 461 protected: |
423 // Provide locked versions to get precise counts. | 462 // Provide locked versions to get precise counts. |
424 virtual void Accumulate(Sample value, Count count, size_t index); | 463 virtual void Accumulate(Sample value, Count count, size_t index); |
425 | 464 |
426 virtual void SnapshotSample(SampleSet* sample); | 465 virtual void SnapshotSample(SampleSet* sample); |
427 | 466 |
428 private: | 467 private: |
429 Lock lock_; | 468 Lock lock_; |
430 | 469 |
431 DISALLOW_EVIL_CONSTRUCTORS(ThreadSafeHistogram); | 470 DISALLOW_COPY_AND_ASSIGN(ThreadSafeHistogram); |
432 }; | 471 }; |
433 | 472 |
434 //------------------------------------------------------------------------------ | 473 //------------------------------------------------------------------------------ |
435 // StatisticsRecorder handles all histograms in the system. It provides a | 474 // StatisticsRecorder handles all histograms in the system. It provides a |
436 // general place for histograms to register, and supports a global API for | 475 // general place for histograms to register, and supports a global API for |
437 // accessing (i.e., dumping, or graphing) the data in all the histograms. | 476 // accessing (i.e., dumping, or graphing) the data in all the histograms. |
438 | 477 |
439 class StatisticsRecorder { | 478 class StatisticsRecorder { |
440 public: | 479 public: |
441 typedef std::vector<const Histogram*> Histograms; | 480 typedef std::vector<Histogram*> Histograms; |
442 | 481 |
443 StatisticsRecorder(); | 482 StatisticsRecorder(); |
444 | 483 |
445 ~StatisticsRecorder(); | 484 ~StatisticsRecorder(); |
446 | 485 |
447 // Find out if histograms can now be registered into our list. | 486 // Find out if histograms can now be registered into our list. |
448 static bool WasStarted(); | 487 static bool WasStarted(); |
449 | 488 |
450 // Register, or add a new histogram to the collection of statistics. | 489 // Register, or add a new histogram to the collection of statistics. |
451 // Return true if registered. | 490 // Return true if registered. |
452 static bool Register(const Histogram& histogram); | 491 static bool Register(Histogram* histogram); |
453 // Unregister, or remove, a histogram from the collection of statistics. | 492 // Unregister, or remove, a histogram from the collection of statistics. |
454 static void UnRegister(const Histogram& histogram); | 493 static void UnRegister(Histogram* histogram); |
455 | 494 |
456 // Methods for printing histograms. Only histograms which have query as | 495 // Methods for printing histograms. Only histograms which have query as |
457 // a substring are written to output (an empty string will process all | 496 // a substring are written to output (an empty string will process all |
458 // registered histograms). | 497 // registered histograms). |
459 static void WriteHTMLGraph(const std::string& query, std::string* output); | 498 static void WriteHTMLGraph(const std::string& query, std::string* output); |
460 static void WriteGraph(const std::string& query, std::string* output); | 499 static void WriteGraph(const std::string& query, std::string* output); |
461 | 500 |
462 // Method for extracting histograms which were marked for use by UMA. | 501 // Method for extracting histograms which were marked for use by UMA. |
463 static void GetHistograms(Histograms* output); | 502 static void GetHistograms(Histograms* output); |
464 | 503 |
| 504 static Histogram* GetHistogram(const std::string& query); |
| 505 |
465 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } | 506 static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } |
466 | 507 |
467 private: | |
468 typedef std::map<std::string, const Histogram*> HistogramMap; | |
469 // We keep all registered histograms in a map, from name to histogram. | |
470 | |
471 // GetSnapshot copies some of the pointers to registered histograms into the | 508 // GetSnapshot copies some of the pointers to registered histograms into the |
472 // caller supplied vector (Histograms). Only histograms with names matching | 509 // caller supplied vector (Histograms). Only histograms with names matching |
473 // query are returned. The query must be a substring of histogram name for its | 510 // query are returned. The query must be a substring of histogram name for its |
474 // pointer to be copied. | 511 // pointer to be copied. |
475 static void GetSnapshot(const std::string& query, Histograms* snapshot); | 512 static void GetSnapshot(const std::string& query, Histograms* snapshot); |
476 | 513 |
| 514 |
| 515 private: |
| 516 // We keep all registered histograms in a map, from name to histogram. |
| 517 typedef std::map<std::string, Histogram*> HistogramMap; |
| 518 |
477 static HistogramMap* histograms_; | 519 static HistogramMap* histograms_; |
| 520 |
478 // lock protects access to the above map. | 521 // lock protects access to the above map. |
479 static Lock* lock_; | 522 static Lock* lock_; |
480 | 523 |
481 // Dump all known histograms to log. | 524 // Dump all known histograms to log. |
482 static bool dump_on_exit_; | 525 static bool dump_on_exit_; |
483 | 526 |
484 DISALLOW_EVIL_CONSTRUCTORS(StatisticsRecorder); | 527 DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder); |
485 }; | 528 }; |
486 | 529 |
487 #endif // BASE_HISTOGRAM_H__ | 530 #endif // BASE_HISTOGRAM_H__ |
OLD | NEW |