summaryrefslogtreecommitdiffstats
path: root/o3d/statsreport
diff options
context:
space:
mode:
Diffstat (limited to 'o3d/statsreport')
-rw-r--r--o3d/statsreport/aggregator-mac.h77
-rw-r--r--o3d/statsreport/aggregator-mac.mm152
-rw-r--r--o3d/statsreport/aggregator-posix-inl.h61
-rw-r--r--o3d/statsreport/aggregator-posix.cc193
-rw-r--r--o3d/statsreport/aggregator-posix.h84
-rw-r--r--o3d/statsreport/aggregator-win32.cc172
-rw-r--r--o3d/statsreport/aggregator-win32.h104
-rw-r--r--o3d/statsreport/aggregator-win32_unittest.cc116
-rw-r--r--o3d/statsreport/aggregator-win32_unittest.h78
-rw-r--r--o3d/statsreport/aggregator.cc94
-rw-r--r--o3d/statsreport/aggregator.h77
-rw-r--r--o3d/statsreport/aggregator_unittest.cc140
-rw-r--r--o3d/statsreport/aggregator_unittest.h85
-rw-r--r--o3d/statsreport/build.scons71
-rw-r--r--o3d/statsreport/common/build.scons53
-rw-r--r--o3d/statsreport/common/const_product.h91
-rw-r--r--o3d/statsreport/common/highres_timer-linux.cc59
-rw-r--r--o3d/statsreport/common/highres_timer-linux.h106
-rw-r--r--o3d/statsreport/common/highres_timer-mac.cc70
-rw-r--r--o3d/statsreport/common/highres_timer-mac.h103
-rw-r--r--o3d/statsreport/common/highres_timer-win32.cc72
-rw-r--r--o3d/statsreport/common/highres_timer-win32.h105
-rw-r--r--o3d/statsreport/common/highres_timer.h40
-rw-r--r--o3d/statsreport/common/highres_timer_unittest.cc84
-rw-r--r--o3d/statsreport/const-mac.h52
-rw-r--r--o3d/statsreport/const-mac.mm69
-rw-r--r--o3d/statsreport/const-posix.cc44
-rw-r--r--o3d/statsreport/const-posix.h49
-rw-r--r--o3d/statsreport/const-win32.cc46
-rw-r--r--o3d/statsreport/const-win32.h48
-rw-r--r--o3d/statsreport/const_server.h54
-rw-r--r--o3d/statsreport/formatter.cc93
-rw-r--r--o3d/statsreport/formatter.h79
-rw-r--r--o3d/statsreport/formatter_unittest.cc54
-rw-r--r--o3d/statsreport/lock.h63
-rw-r--r--o3d/statsreport/metrics.cc272
-rw-r--r--o3d/statsreport/metrics.h561
-rw-r--r--o3d/statsreport/metrics_unittest.cc407
-rw-r--r--o3d/statsreport/persistent_iterator-win32.cc163
-rw-r--r--o3d/statsreport/persistent_iterator-win32.h152
-rw-r--r--o3d/statsreport/persistent_iterator-win32_unittest.cc164
-rw-r--r--o3d/statsreport/uploader-mac.mm97
-rw-r--r--o3d/statsreport/uploader-posix.cc76
-rw-r--r--o3d/statsreport/uploader-win32.cc106
-rw-r--r--o3d/statsreport/uploader.h75
-rw-r--r--o3d/statsreport/uploader_aggregation-mac.mm245
-rw-r--r--o3d/statsreport/uploader_aggregation-posix.cc150
-rw-r--r--o3d/statsreport/uploader_aggregation-win32.cc190
-rw-r--r--o3d/statsreport/util-win32.h53
49 files changed, 5649 insertions, 0 deletions
diff --git a/o3d/statsreport/aggregator-mac.h b/o3d/statsreport/aggregator-mac.h
new file mode 100644
index 0000000..046e10f
--- /dev/null
+++ b/o3d/statsreport/aggregator-mac.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Mac aggregator, which aggregates counters to a keyvaluetable. It is the
+// interface to the keyvaluetable for all clients.
+
+#ifndef O3D_STATSREPORT_AGGREGATOR_MAC_H__
+#define O3D_STATSREPORT_AGGREGATOR_MAC_H__
+
+#include <Cocoa/Cocoa.h>
+
+#include <string>
+#include "statsreport/aggregator.h"
+#include "base/scoped_ptr.h"
+
+namespace stats_report {
+
+class Formatter;
+
+class MetricsAggregatorMac: public MetricsAggregator {
+ public:
+ // @param coll the metrics collection to aggregate, most usually this
+ // is g_global_metrics.
+ explicit MetricsAggregatorMac(const MetricCollection &coll);
+ virtual ~MetricsAggregatorMac();
+
+
+ protected:
+ virtual bool StartAggregation();
+ virtual void EndAggregation();
+
+ virtual void Aggregate(CountMetric *metric);
+ virtual void Aggregate(TimingMetric *metric);
+ virtual void Aggregate(IntegerMetric *metric);
+ virtual void Aggregate(BoolMetric *metric);
+
+ private:
+ NSAutoreleasePool *pool_;
+ NSMutableDictionary *dict_;
+ NSString *storePath_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsAggregatorMac);
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_AGGREGATOR_MAC_H__
+
diff --git a/o3d/statsreport/aggregator-mac.mm b/o3d/statsreport/aggregator-mac.mm
new file mode 100644
index 0000000..69699ab
--- /dev/null
+++ b/o3d/statsreport/aggregator-mac.mm
@@ -0,0 +1,152 @@
+
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of a Mac metrics aggregator.
+
+#include "aggregator-mac.h"
+#include "const-mac.h"
+#include "formatter.h"
+
+
+namespace stats_report {
+
+
+MetricsAggregatorMac::MetricsAggregatorMac(const MetricCollection &coll)
+ : MetricsAggregator(coll),
+ dict_(nil),
+ pool_(nil){
+ storePath_ = O3DStatsPath();
+}
+
+MetricsAggregatorMac::~MetricsAggregatorMac() {
+}
+
+
+bool MetricsAggregatorMac::StartAggregation() {
+ pool_ = [[NSAutoreleasePool alloc] init];
+ dict_ = [NSMutableDictionary dictionaryWithContentsOfFile:storePath_];
+ if (dict_ == nil)
+ dict_ = [[[NSMutableDictionary alloc] init] autorelease];
+
+ return true;
+}
+
+void MetricsAggregatorMac::EndAggregation() {
+ [dict_ writeToFile:storePath_ atomically:YES];
+ dict_ = nil; // it will get autoreleased when the pool dies
+
+ [pool_ release];
+ pool_ = nil;
+}
+
+void MetricsAggregatorMac::Aggregate(CountMetric *metric) {
+ // do as little as possible if no value
+ uint64 value = metric->Reset();
+ if (0 == value)
+ return;
+
+ NSString *keyName = [NSString stringWithFormat:@"C_%s", metric->name()];
+ NSNumber *previousValue = [dict_ objectForKey:keyName];
+ if (previousValue == nil)
+ previousValue = [NSNumber numberWithLongLong:0];
+
+ NSNumber *newTotal =
+ [NSNumber numberWithLongLong:value + [previousValue longLongValue]];
+ [dict_ setObject:newTotal forKey:keyName];
+}
+
+
+static long long LLMin(long long a, long long b) {
+ return a < b ? a : b;
+}
+
+static long long LLMax(long long a, long long b) {
+ return a > b ? a : b;
+}
+
+void MetricsAggregatorMac::Aggregate(TimingMetric *metric) {
+ // do as little as possible if no value
+ TimingMetric::TimingData newValue = metric->Reset();
+ if (0 == newValue.count)
+ return;
+
+ NSString *keyName = [NSString stringWithFormat:@"T_%s", metric->name()];
+ NSArray *previousValue = [dict_ objectForKey:keyName];
+ NSArray *newTotal = nil;
+
+ if (previousValue == nil) {
+ newTotal = [NSArray arrayWithObjects:
+ [NSNumber numberWithInt:newValue.count],
+ [NSNumber numberWithLongLong:newValue.sum],
+ [NSNumber numberWithLongLong:newValue.minimum],
+ [NSNumber numberWithLongLong:newValue.maximum],
+ nil];
+ } else {
+ int previousCount = [[previousValue objectAtIndex:0] intValue];
+ long long previousSum = [[previousValue objectAtIndex:1] longLongValue];
+ long long previousMin = [[previousValue objectAtIndex:2] longLongValue];
+ long long previousMax = [[previousValue objectAtIndex:3] longLongValue];
+
+ newTotal =
+ [NSArray arrayWithObjects:
+ [NSNumber numberWithInt:newValue.count + previousCount],
+ [NSNumber numberWithLongLong:newValue.sum + previousSum],
+ [NSNumber numberWithLongLong:LLMin(newValue.minimum, previousMin)],
+ [NSNumber numberWithLongLong:LLMax(newValue.maximum, previousMax)],
+ nil];
+ }
+
+ [dict_ setObject:newTotal forKey:keyName];
+}
+
+void MetricsAggregatorMac::Aggregate(IntegerMetric *metric) {
+ // do as little as possible if no value
+ int64 value = metric->value(); // yes, we only have 63 positive bits here :(
+ if (0 == value)
+ return;
+
+ NSString *keyName = [NSString stringWithFormat:@"I_%s", metric->name()];
+ [dict_ setObject:[NSNumber numberWithLongLong:value] forKey:keyName];
+}
+
+void MetricsAggregatorMac::Aggregate(BoolMetric *metric) {
+ // do as little as possible if no value
+ int32 value = metric->Reset();
+ if (BoolMetric::kBoolUnset == value)
+ return;
+
+ NSString *keyName = [NSString stringWithFormat:@"B_%s", metric->name()];
+ [dict_ setObject:[NSNumber numberWithBool:(value != 0)] forKey:keyName];
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/aggregator-posix-inl.h b/o3d/statsreport/aggregator-posix-inl.h
new file mode 100644
index 0000000..e147bf6
--- /dev/null
+++ b/o3d/statsreport/aggregator-posix-inl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Posix aggregator inlines.
+
+#ifndef O3D_STATSREPORT_AGGREGATOR_POSIX_INL_H__
+#define O3D_STATSREPORT_AGGREGATOR_POSIX_INL_H__
+
+#include <string>
+#include "aggregator-posix.h"
+
+namespace stats_report {
+
+template <typename ValueType>
+bool MetricsAggregatorPosix::GetValue(const string &key, ValueType *value) {
+ StartAggregation();
+ bool success = transaction_->Get(key, value);
+ EndAggregation();
+ return success;
+}
+
+template <typename ValueType>
+bool MetricsAggregatorPosix::SetValue(const string &key, ValueType value) {
+ StartAggregation();
+ bool success = transaction_->Put(key, value);
+ EndAggregation();
+ return success;
+}
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_AGGREGATOR_POSIX_INL_H__
diff --git a/o3d/statsreport/aggregator-posix.cc b/o3d/statsreport/aggregator-posix.cc
new file mode 100644
index 0000000..11e99fa
--- /dev/null
+++ b/o3d/statsreport/aggregator-posix.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of a Posix metrics aggregator.
+
+#include "aggregator-posix.h"
+#include "const-posix.h"
+#include "formatter.h"
+#include "util/endian/endian.h"
+#include "statsreport/common/pathhelpers.h"
+
+namespace stats_report {
+
+MetricsAggregatorPosix::MetricsAggregatorPosix(const MetricCollection &coll) {
+ key_value_table_.reset(new KeyValueTable(get_cache_dir() + "stats.sqlite3",
+ "stats"));
+}
+
+MetricsAggregatorPosix::~MetricsAggregatorPosix() {
+}
+
+void MetricsAggregatorPosix::ResetMetrics() {
+ StartAggregation();
+ (void)transaction_->Clear();
+ EndAggregation();
+}
+
+namespace {
+
+void AddMetric(const string& key,
+ const ScopedStatement &statement,
+ void *ref_con) {
+ Formatter *formatter =
+ static_cast<Formatter *>(ref_con);
+
+ string original_key;
+ scoped_ptr<MetricBase> metric;
+
+ if (key.compare(0, kCountsKeyName.length(), kCountsKeyName) == 0) {
+ int64 value;
+ GetColumn(statement.get(), 0, &value);
+ original_key = key.substr(kCountsKeyName.length());
+ metric.reset(new CountMetric(original_key.c_str(), value));
+ } else if (key.compare(0, kTimingsKeyName.length(), kTimingsKeyName) == 0) {
+ std::vector<BYTE> value_bytes;
+ TimingMetric::TimingData value;
+ GetColumn(statement.get(), 0, &value_bytes);
+ memcpy(&value, &value_bytes[0], value_bytes.size());
+ value.count = gntohl(value.count);
+ value.sum = gntohll(value.sum);
+ value.minimum = gntohll(value.minimum);
+ value.maximum = gntohll(value.maximum);
+ metric.reset(new TimingMetric(original_key.c_str(), value));
+ } else if (key.compare(0, kIntegersKeyName.length(), kIntegersKeyName) == 0) {
+ int64 value;
+ GetColumn(statement.get(), 0, &value);
+ original_key = key.substr(kIntegersKeyName.length());
+ metric.reset(new IntegerMetric(original_key.c_str(), value));
+ } else if (key.compare(0, kBooleansKeyName.length(), kBooleansKeyName) == 0) {
+ int32 value;
+ GetColumn(statement.get(), 0, &value);
+ original_key = key.substr(kBooleansKeyName.length());
+ metric.reset(new BoolMetric(original_key.c_str(), value));
+ }
+
+ if (!original_key.empty())
+ formatter->AddMetric(&*metric);
+}
+
+} // namespace
+
+void MetricsAggregatorPosix::FormatMetrics(Formatter *formatter) {
+ StartAggregation();
+ transaction_->Iterate(AddMetric, formatter);
+ EndAggregation();
+}
+
+bool MetricsAggregatorPosix::StartAggregation() {
+ transaction_.reset(new KeyValueTransaction(&*key_value_table_));
+
+ return true;
+}
+
+void MetricsAggregatorPosix::EndAggregation() {
+ transaction_.reset();
+}
+
+void MetricsAggregatorPosix::Aggregate(CountMetric *metric) {
+ // do as little as possible if no value
+ uint64 value = metric->Reset();
+ if (0 == value)
+ return;
+
+ string name(metric->name());
+ name.insert(0, kCountsKeyName);
+ int64 reg_value = 0; // yes, we only have 63 positive bits here :(
+ if (!transaction_->Get(name, &reg_value)) {
+ // TODO: clean up??
+ }
+ reg_value += value;
+
+ (void)transaction_->Put(name, reg_value);
+}
+
+void MetricsAggregatorPosix::Aggregate(TimingMetric *metric) {
+ // do as little as possible if no value
+ TimingMetric::TimingData value = metric->Reset();
+ if (0 == value.count)
+ return;
+
+ string name(metric->name());
+ name.insert(0, kTimingsKeyName);
+ std::vector<BYTE> reg_value_bytes;
+ TimingMetric::TimingData reg_value;
+ if (!transaction_->Get(name, &reg_value_bytes)) {
+ reg_value_bytes.resize(sizeof(reg_value));
+ memcpy(&reg_value, &value, sizeof(value));
+ } else {
+ memcpy(&reg_value, &reg_value_bytes[0], reg_value_bytes.size());
+ reg_value.count = gntohl(reg_value.count);
+ reg_value.sum = gntohll(reg_value.sum);
+ reg_value.minimum = gntohll(reg_value.minimum);
+ reg_value.maximum = gntohll(reg_value.maximum);
+
+ reg_value.count += value.count;
+ reg_value.sum += value.sum;
+ reg_value.minimum = std::min(reg_value.minimum, value.minimum);
+ reg_value.maximum = std::max(reg_value.maximum, value.maximum);
+ }
+
+ reg_value.count = ghtonl(reg_value.count);
+ reg_value.sum = ghtonll(reg_value.sum);
+ reg_value.minimum = ghtonll(reg_value.minimum);
+ reg_value.maximum = ghtonll(reg_value.maximum);
+
+ memcpy(&reg_value_bytes[0], &reg_value, sizeof(reg_value));
+ (void)transaction_->Put(name, reg_value_bytes);
+}
+
+void MetricsAggregatorPosix::Aggregate(IntegerMetric *metric) {
+ // do as little as possible if no value
+ int64 value = metric->value(); // yes, we only have 63 positive bits here :(
+ if (0 == value)
+ return;
+
+ string name(metric->name());
+ name.insert(0, kIntegersKeyName);
+
+ (void)transaction_->Put(name, value);
+}
+
+void MetricsAggregatorPosix::Aggregate(BoolMetric *metric) {
+ // do as little as possible if no value
+ int32 value = metric->Reset();
+ if (BoolMetric::kBoolUnset == value)
+ return;
+
+ string name(metric->name());
+ name.insert(0, kBooleansKeyName);
+
+ (void)transaction_->Put(name, value);
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/aggregator-posix.h b/o3d/statsreport/aggregator-posix.h
new file mode 100644
index 0000000..10117a4
--- /dev/null
+++ b/o3d/statsreport/aggregator-posix.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Posix aggregator, which aggregates counters to a keyvaluetable. It is the
+// interface to the keyvaluetable for all clients.
+
+#ifndef O3D_STATSREPORT_AGGREGATOR_POSIX_H__
+#define O3D_STATSREPORT_AGGREGATOR_POSIX_H__
+
+#include <string>
+#include "aggregator.h"
+#include "base/scoped_ptr.h"
+#include "backend/keyvaluetable.h"
+
+namespace stats_report {
+
+class Formatter;
+
+class MetricsAggregatorPosix: public MetricsAggregator {
+ public:
+ // @param coll the metrics collection to aggregate, most usually this
+ // is g_global_metrics.
+ explicit MetricsAggregatorPosix(const MetricCollection &coll);
+ ~MetricsAggregatorPosix();
+
+ template <typename ValueType>
+ bool GetValue(const string &key, ValueType *value);
+ template <typename ValueType>
+ bool SetValue(const string &key, ValueType value);
+
+ void ResetMetrics();
+ void FormatMetrics(Formatter *formatter);
+
+ protected:
+ virtual bool StartAggregation();
+ virtual void EndAggregation();
+
+ virtual void Aggregate(CountMetric *metric);
+ virtual void Aggregate(TimingMetric *metric);
+ virtual void Aggregate(IntegerMetric *metric);
+ virtual void Aggregate(BoolMetric *metric);
+
+ private:
+ // The keyvaluetable
+ scoped_ptr<KeyValueTable> key_value_table_;
+
+ // The current transaction
+ scoped_ptr<KeyValueTransaction> transaction_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsAggregatorPosix);
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_AGGREGATOR_POSIX_H__
diff --git a/o3d/statsreport/aggregator-win32.cc b/o3d/statsreport/aggregator-win32.cc
new file mode 100644
index 0000000..2f5678b
--- /dev/null
+++ b/o3d/statsreport/aggregator-win32.cc
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of Win32 metrics aggregator.
+#include "aggregator-win32.h"
+#include "const-win32.h"
+#include "util-win32.h"
+
+namespace stats_report {
+
+MetricsAggregatorWin32::MetricsAggregatorWin32(const MetricCollection &coll,
+ const wchar_t *key_name)
+ : MetricsAggregator(coll),
+ is_machine_(false) {
+ DCHECK(NULL != key_name);
+
+ key_name_.Format(kStatsKeyFormatString, key_name);
+}
+
+MetricsAggregatorWin32::MetricsAggregatorWin32(const MetricCollection &coll,
+ const wchar_t *key_name,
+ bool is_machine)
+ : MetricsAggregator(coll),
+ is_machine_(is_machine) {
+ DCHECK(NULL != key_name);
+
+ key_name_.Format(kStatsKeyFormatString, key_name);
+}
+
+MetricsAggregatorWin32::~MetricsAggregatorWin32() {
+}
+
+bool MetricsAggregatorWin32::StartAggregation() {
+ DCHECK(NULL == key_.m_hKey);
+
+ HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ LONG err = key_.Create(parent_key, key_name_);
+ if (err != ERROR_SUCCESS)
+ return false;
+
+ return true;
+}
+
+void MetricsAggregatorWin32::EndAggregation() {
+ count_key_.Close();
+ timing_key_.Close();
+ integer_key_.Close();
+ bool_key_.Close();
+
+ key_.Close();
+}
+
+bool MetricsAggregatorWin32::EnsureKey(const wchar_t *name, CRegKey *key) {
+ if (NULL != key->m_hKey)
+ return true;
+
+ LONG err = key->Create(key_, name);
+ if (ERROR_SUCCESS != err) {
+ DCHECK(NULL == key->m_hKey);
+ // TODO: log?
+ return false;
+ }
+
+ return true;
+}
+
+void MetricsAggregatorWin32::Aggregate(CountMetric *metric) {
+ DCHECK(NULL != metric);
+
+ // do as little as possible if no value
+ uint64 value = metric->Reset();
+ if (0 == value)
+ return;
+
+ if (!EnsureKey(kCountsKeyName, &count_key_))
+ return;
+
+ CString name(metric->name());
+ uint64 reg_value = 0;
+ if (!GetData(&count_key_, name, &reg_value)) {
+ // TODO: clean up??
+ }
+ reg_value += value;
+
+ DWORD err = count_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));
+}
+
+void MetricsAggregatorWin32::Aggregate(TimingMetric *metric) {
+ DCHECK(NULL != metric);
+
+ // do as little as possible if no value
+ TimingMetric::TimingData value = metric->Reset();
+ if (0 == value.count)
+ return;
+
+ if (!EnsureKey(kTimingsKeyName, &timing_key_))
+ return;
+
+ CString name(metric->name());
+ TimingMetric::TimingData reg_value;
+ if (!GetData(&timing_key_, name, &reg_value)) {
+ memcpy(&reg_value, &value, sizeof(value));
+ } else {
+ reg_value.count += value.count;
+ reg_value.sum += value.sum;
+ reg_value.minimum = std::min(reg_value.minimum, value.minimum);
+ reg_value.maximum = std::max(reg_value.maximum, value.maximum);
+ }
+
+ DWORD err = timing_key_.SetBinaryValue(name, &reg_value, sizeof(reg_value));
+}
+
+void MetricsAggregatorWin32::Aggregate(IntegerMetric *metric) {
+ DCHECK(NULL != metric);
+
+ // do as little as possible if no value
+ uint64 value = metric->value();
+ if (0 == value)
+ return;
+
+ if (!EnsureKey(kIntegersKeyName, &integer_key_))
+ return;
+
+ DWORD err = integer_key_.SetBinaryValue(CString(metric->name()),
+ &value, sizeof(value));
+}
+
+void MetricsAggregatorWin32::Aggregate(BoolMetric *metric) {
+ DCHECK(NULL != metric);
+
+ // do as little as possible if no value
+ int32 value = metric->Reset();
+ if (BoolMetric::kBoolUnset == value)
+ return;
+
+ if (!EnsureKey(kBooleansKeyName, &bool_key_))
+ return;
+
+ DWORD err = bool_key_.SetBinaryValue(CString(metric->name()),
+ &value, sizeof(value));
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/aggregator-win32.h b/o3d/statsreport/aggregator-win32.h
new file mode 100644
index 0000000..566de62
--- /dev/null
+++ b/o3d/statsreport/aggregator-win32.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Win32 aggregator, which aggregates counters to registry under a named
+// Mutex lock.
+#ifndef O3D_STATSREPORT_AGGREGATOR_WIN32_H__
+#define O3D_STATSREPORT_AGGREGATOR_WIN32_H__
+
+#include "aggregator.h"
+#include <atlbase.h>
+#include <atlstr.h>
+
+namespace stats_report {
+
+class MetricsAggregatorWin32: public MetricsAggregator {
+ public:
+ // @param coll the metrics collection to aggregate, most usually this
+ // is g_global_metrics.
+ // @param app_name name of the subkey under HKCU\Software\Google we
+ // aggregate to. Should be or encode the application name for
+ // transparency, e.g. "Scour", or "Gears".
+ MetricsAggregatorWin32(const MetricCollection &coll,
+ const wchar_t *app_name);
+
+ // @param is_machine specifies the registry hive where the stats are
+ // aggregated to.
+ MetricsAggregatorWin32(const MetricCollection &coll,
+ const wchar_t *app_name,
+ bool is_machine);
+ virtual ~MetricsAggregatorWin32();
+
+ protected:
+ virtual bool StartAggregation();
+ virtual void EndAggregation();
+
+ virtual void Aggregate(CountMetric *metric);
+ virtual void Aggregate(TimingMetric *metric);
+ virtual void Aggregate(IntegerMetric *metric);
+ virtual void Aggregate(BoolMetric *metric);
+ private:
+ enum {
+ // Max length of time we wait for the mutex on StartAggregation.
+ kMaxMutexWaitMs = 1000, // 1 second for now
+ };
+
+ // Ensures that *key is open, opening it if it's NULL
+ // @return true on success, false on failure to open key
+ bool EnsureKey(const wchar_t *name, CRegKey *key);
+
+ // Mutex name for locking access to key
+ CString mutex_name_;
+
+ // Subkey name, as per constructor docs
+ CString key_name_;
+
+ // Handle to our subkey under HKCU\Software\Google
+ CRegKey key_;
+
+ // Subkeys under the above
+ // @{
+ CRegKey count_key_;
+ CRegKey timing_key_;
+ CRegKey integer_key_;
+ CRegKey bool_key_;
+ // @}
+
+ // Specifies HKLM or HKCU, respectively.
+ bool is_machine_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsAggregatorWin32);
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_AGGREGATOR_WIN32_H__
diff --git a/o3d/statsreport/aggregator-win32_unittest.cc b/o3d/statsreport/aggregator-win32_unittest.cc
new file mode 100644
index 0000000..451927b
--- /dev/null
+++ b/o3d/statsreport/aggregator-win32_unittest.cc
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of Win32 metrics aggregator.
+#include "aggregator-win32.h"
+#include "aggregator-win32_unittest.h"
+#include "aggregator_unittest.h"
+#include "gtest/gtest.h"
+
+using ::stats_report::MetricsAggregatorWin32;
+using ::stats_report::TimingMetric;
+
+#define APP_NAME_STRING L"aggregator-win32_unittest"
+#define PREFIX_KEY_STRING L"Software\\Google\\"
+#define SUFFIX_KEY_STRING L"\\UsageStats\\Daily"
+#define ROOT_KEY_STRING PREFIX_KEY_STRING APP_NAME_STRING
+#define KEY_STRING ROOT_KEY_STRING SUFFIX_KEY_STRING
+
+const wchar_t MetricsAggregatorWin32Test::kAppName[] = APP_NAME_STRING;
+const wchar_t MetricsAggregatorWin32Test::kRootKeyName[] = ROOT_KEY_STRING;
+const wchar_t MetricsAggregatorWin32Test::kCountsKeyName[] =
+ KEY_STRING L"\\Counts";
+const wchar_t MetricsAggregatorWin32Test::kTimingsKeyName[] =
+ KEY_STRING L"\\Timings";
+const wchar_t MetricsAggregatorWin32Test::kIntegersKeyName[] =
+ KEY_STRING L"\\Integers";
+const wchar_t MetricsAggregatorWin32Test::kBoolsKeyName[] =
+ KEY_STRING L"\\Booleans";
+
+
+#define EXPECT_REGVAL_EQ(value, key_name, value_name) do { \
+ char buf[sizeof(value)]; \
+ ULONG len = sizeof(buf); \
+ CRegKey key; \
+ ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, key_name)); \
+ EXPECT_EQ(ERROR_SUCCESS, key.QueryBinaryValue(value_name, buf, &len)); \
+ EXPECT_EQ(sizeof(buf), len); \
+ EXPECT_EQ(0, memcmp(&value, buf, sizeof(buf))); \
+ } while (0)
+
+TEST_F(MetricsAggregatorWin32Test, AggregateWin32) {
+ MetricsAggregatorWin32 agg(coll_, kAppName);
+
+ EXPECT_TRUE(agg.AggregateMetrics());
+ AddStats();
+ EXPECT_TRUE(agg.AggregateMetrics());
+
+ {
+ int64 one = 1, two = 2;
+ EXPECT_REGVAL_EQ(one, kCountsKeyName, L"c1");
+ EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c2");
+
+ TimingMetric::TimingData data1 = { 2, 0, 1500, 500, 1000 };
+ TimingMetric::TimingData data2 = { 2, 0, 2030, 30, 2000 };
+ EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");
+ EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");
+
+ EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");
+ EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");
+
+ int32 bool_true = 1, bool_false = 0;
+ EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");
+ EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");
+ }
+
+ AddStats();
+ EXPECT_TRUE(agg.AggregateMetrics());
+
+ {
+ int64 two = 2, four = 4;
+ EXPECT_REGVAL_EQ(two, kCountsKeyName, L"c1");
+ EXPECT_REGVAL_EQ(four, kCountsKeyName, L"c2");
+
+ TimingMetric::TimingData data1 = { 4, 0, 3000, 500, 1000 };
+ TimingMetric::TimingData data2 = { 4, 0, 4060, 30, 2000 };
+ EXPECT_REGVAL_EQ(data1, kTimingsKeyName, L"t1");
+ EXPECT_REGVAL_EQ(data2, kTimingsKeyName, L"t2");
+
+ int64 one = 1;
+ EXPECT_REGVAL_EQ(one, kIntegersKeyName, L"i1");
+ EXPECT_REGVAL_EQ(two, kIntegersKeyName, L"i2");
+
+ int32 bool_true = 1, bool_false = 0;
+ EXPECT_REGVAL_EQ(bool_true, kBoolsKeyName, L"b1");
+ EXPECT_REGVAL_EQ(bool_false, kBoolsKeyName, L"b2");
+ }
+}
diff --git a/o3d/statsreport/aggregator-win32_unittest.h b/o3d/statsreport/aggregator-win32_unittest.h
new file mode 100644
index 0000000..ceefc90
--- /dev/null
+++ b/o3d/statsreport/aggregator-win32_unittest.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
+#define O3D_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
+
+#include "aggregator_unittest.h"
+#include "aggregator-win32.h"
+
+// Shared test fixture for win32 unit tests
+class MetricsAggregatorWin32Test: public MetricsAggregatorTest {
+ public:
+ virtual void SetUp() {
+ // clean the registry
+ SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);
+ MetricsAggregatorTest::SetUp();
+ }
+ virtual void TearDown() {
+ MetricsAggregatorTest::TearDown();
+ SHDeleteKey(HKEY_CURRENT_USER, kRootKeyName);
+ }
+
+ void AddStats() {
+ ++c1_;
+ ++c2_;
+ ++c2_;
+
+ t1_.AddSample(1000);
+ t1_.AddSample(500);
+
+ t2_.AddSample(2000);
+ t2_.AddSample(30);
+
+ i1_ = 1;
+ i2_ = 2;
+
+ b1_ = true;
+ b2_ = false;
+ }
+
+ static const wchar_t kAppName[];
+ static const wchar_t kRootKeyName[];
+ static const wchar_t kCountsKeyName[];
+ static const wchar_t kTimingsKeyName[];
+ static const wchar_t kIntegersKeyName[];
+ static const wchar_t kBoolsKeyName[];
+};
+
+#endif // O3D_STATSREPORT_AGGREGATOR_WIN32_UNITTEST_H__
diff --git a/o3d/statsreport/aggregator.cc b/o3d/statsreport/aggregator.cc
new file mode 100644
index 0000000..41e6fbf
--- /dev/null
+++ b/o3d/statsreport/aggregator.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of helper classes to aggregate the collected in-memory
+// stats to persistent storage.
+#include "aggregator.h"
+
+namespace stats_report {
+
+bool MetricsAggregator::AggregateMetrics() {
+ if (!StartAggregation())
+ return false;
+
+ MetricIterator it(coll_), end;
+ for (; it != end; ++it) {
+ MetricBase *metric = *it;
+ DCHECK(NULL != metric);
+
+ switch (metric->type()) {
+ case kCountType:
+ Aggregate(metric->AsCount());
+ break;
+ case kTimingType:
+ Aggregate(metric->AsTiming());
+ break;
+ case kIntegerType:
+ Aggregate(metric->AsInteger());
+ break;
+ case kBoolType:
+ Aggregate(metric->AsBool());
+ break;
+ default:
+ DCHECK(false && "Impossible metric type");
+ break;
+ }
+ }
+
+ // done, close up
+ EndAggregation();
+
+ return true;
+}
+
+MetricsAggregator::MetricsAggregator() : coll_(g_global_metrics) {
+ DCHECK(coll_.initialized());
+}
+
+MetricsAggregator::MetricsAggregator(const MetricCollection &coll)
+ : coll_(coll) {
+ DCHECK(coll_.initialized());
+}
+
+MetricsAggregator::~MetricsAggregator() {
+}
+
+bool MetricsAggregator::StartAggregation() {
+ // nothing
+ return true;
+}
+
+void MetricsAggregator::EndAggregation() {
+ // nothing
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/aggregator.h b/o3d/statsreport/aggregator.h
new file mode 100644
index 0000000..f5e84e4
--- /dev/null
+++ b/o3d/statsreport/aggregator.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to aggregate the collected in-memory stats to persistent
+// storage.
+#ifndef O3D_STATSREPORT_AGGREGATOR_H__
+#define O3D_STATSREPORT_AGGREGATOR_H__
+
+#include "metrics.h"
+
+namespace stats_report {
+// TODO: Refactor to avoid cross platform code duplication.
+
+// Wrapper class and interface for metrics aggregation. This is a platform
+// independent class and needs to be subclassed for various platforms and/or
+// metrics persistence methods
+class MetricsAggregator {
+ public:
+ // Aggregate all metrics in the associated collection
+ // @returns true iff aggregation started successfully, false otherwise.
+ bool AggregateMetrics();
+
+ protected:
+ MetricsAggregator();
+ explicit MetricsAggregator(const MetricCollection &coll);
+ virtual ~MetricsAggregator();
+
+ // Start aggregation. Override this to grab locks, open files, whatever
+ // needs to happen or can expedite the individual aggregate steps.
+ // @return true on success, false on failure.
+ // @note aggregation will not progress if this function returns false
+ virtual bool StartAggregation();
+ virtual void EndAggregation();
+
+ virtual void Aggregate(CountMetric *metric) = 0;
+ virtual void Aggregate(TimingMetric *metric) = 0;
+ virtual void Aggregate(IntegerMetric *metric) = 0;
+ virtual void Aggregate(BoolMetric *metric) = 0;
+
+ private:
+ const MetricCollection &coll_;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricsAggregator);
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_AGGREGATOR_H__
diff --git a/o3d/statsreport/aggregator_unittest.cc b/o3d/statsreport/aggregator_unittest.cc
new file mode 100644
index 0000000..44c65cd
--- /dev/null
+++ b/o3d/statsreport/aggregator_unittest.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implementation of helper classes to aggregate the collected in-memory
+// stats to persistent storage.
+#include "aggregator.h"
+#include "aggregator_unittest.h"
+#include "gtest/gtest.h"
+
+using namespace stats_report;
+
+class TestMetricsAggregator: public MetricsAggregator {
+ public:
+ explicit TestMetricsAggregator(const MetricCollection &coll)
+ : MetricsAggregator(coll), aggregating_(false), counts_(0),
+ timings_(0), integers_(0), bools_(0) {
+ }
+
+ ~TestMetricsAggregator() {
+ }
+
+ bool aggregating() const { return aggregating_; }
+ int counts() const { return counts_; }
+ int timings() const { return timings_; }
+ int integers() const { return integers_; }
+ int bools() const { return bools_; }
+
+ protected:
+ virtual bool StartAggregation() {
+ aggregating_ = true;
+ counts_ = 0;
+ timings_ = 0;
+ integers_ = 0;
+ bools_ = 0;
+
+ return true;
+ }
+
+ virtual void EndAggregation() {
+ aggregating_ = false;
+ }
+
+ virtual void Aggregate(CountMetric *metric) {
+ ASSERT_TRUE(NULL != metric);
+ EXPECT_TRUE(aggregating());
+ metric->Reset();
+ ++counts_;
+ }
+
+ virtual void Aggregate(TimingMetric *metric) {
+ ASSERT_TRUE(NULL != metric);
+ EXPECT_TRUE(aggregating());
+ metric->Reset();
+ ++timings_;
+ }
+ virtual void Aggregate(IntegerMetric *metric) {
+ ASSERT_TRUE(NULL != metric);
+ EXPECT_TRUE(aggregating());
+ // Integer metrics don't get reset on aggregation
+ ++integers_;
+ }
+ virtual void Aggregate(BoolMetric *metric) {
+ ASSERT_TRUE(NULL != metric);
+ EXPECT_TRUE(aggregating());
+ metric->Reset();
+ ++bools_;
+ }
+
+ private:
+ bool aggregating_;
+ int counts_;
+ int timings_;
+ int integers_;
+ int bools_;
+};
+
+TEST_F(MetricsAggregatorTest, Aggregate) {
+ TestMetricsAggregator agg(coll_);
+
+ EXPECT_FALSE(agg.aggregating());
+ EXPECT_EQ(0, agg.counts());
+ EXPECT_EQ(0, agg.timings());
+ EXPECT_EQ(0, agg.integers());
+ EXPECT_EQ(0, agg.bools());
+ EXPECT_TRUE(agg.AggregateMetrics());
+ EXPECT_FALSE(agg.aggregating());
+
+ // check that we saw all counters.
+ EXPECT_TRUE(kNumCounts == agg.counts());
+ EXPECT_TRUE(kNumTimings == agg.timings());
+ EXPECT_TRUE(kNumIntegers == agg.integers());
+ EXPECT_TRUE(kNumBools == agg.bools());
+}
+
+class FailureTestMetricsAggregator: public TestMetricsAggregator {
+ public:
+ explicit FailureTestMetricsAggregator(const MetricCollection &coll) :
+ TestMetricsAggregator(coll) {
+ }
+
+ protected:
+ virtual bool StartAggregation() {
+ return false;
+ }
+};
+
+TEST_F(MetricsAggregatorTest, AggregateFailure) {
+ FailureTestMetricsAggregator agg(coll_);
+
+ EXPECT_FALSE(agg.AggregateMetrics());
+}
diff --git a/o3d/statsreport/aggregator_unittest.h b/o3d/statsreport/aggregator_unittest.h
new file mode 100644
index 0000000..286362e
--- /dev/null
+++ b/o3d/statsreport/aggregator_unittest.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_STATSREPORT_AGGREGATOR_UNITTEST_H__
+#define O3D_STATSREPORT_AGGREGATOR_UNITTEST_H__
+
+#include "metrics.h"
+#include "gtest/gtest.h"
+
+// Test fixture shared among aggregator unit tests
+class MetricsAggregatorTest: public testing::Test {
+ public:
+#define INIT_METRIC(type, name) name##_(#name, &coll_)
+#define DECL_METRIC(type, name) stats_report::type##Metric name##_
+
+ MetricsAggregatorTest()
+ : INIT_METRIC(Count, c1),
+ INIT_METRIC(Count, c2),
+ INIT_METRIC(Timing, t1),
+ INIT_METRIC(Timing, t2),
+ INIT_METRIC(Integer, i1),
+ INIT_METRIC(Integer, i2),
+ INIT_METRIC(Bool, b1),
+ INIT_METRIC(Bool, b2) {
+ }
+
+ enum {
+ kNumCounts = 2,
+ kNumTimings = 2,
+ kNumIntegers = 2,
+ kNumBools = 2
+ };
+
+ stats_report::MetricCollection coll_;
+ DECL_METRIC(Count, c1);
+ DECL_METRIC(Count, c2);
+ DECL_METRIC(Timing, t1);
+ DECL_METRIC(Timing, t2);
+ DECL_METRIC(Integer, i1);
+ DECL_METRIC(Integer, i2);
+ DECL_METRIC(Bool, b1);
+ DECL_METRIC(Bool, b2);
+
+#undef INIT_METRIC
+#undef DECL_METRIC
+
+ virtual void SetUp() {
+ coll_.Initialize();
+ }
+
+ virtual void TearDown() {
+ coll_.Uninitialize();
+ }
+};
+
+#endif // O3D_STATSREPORT_AGGREGATOR_UNITTEST_H__
diff --git a/o3d/statsreport/build.scons b/o3d/statsreport/build.scons
new file mode 100644
index 0000000..8a844c5
--- /dev/null
+++ b/o3d/statsreport/build.scons
@@ -0,0 +1,71 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Import('env')
+
+env.Append(
+ LIBPATH = [ '$LIBS_DIR'
+ ],
+ LIBS = [
+ 'o3d_base',
+ 'o3dStatsreport_Common',
+ ],
+)
+
+INPUTS = [
+ 'aggregator.cc',
+ 'formatter.cc',
+ 'metrics.cc',
+]
+
+if env['TARGET_PLATFORM'] == 'WINDOWS':
+ INPUTS += [
+ 'aggregator-win32.cc',
+ 'const-win32.cc',
+ 'persistent_iterator-win32.cc',
+ 'uploader_aggregation-win32.cc',
+ 'uploader-win32.cc',
+ ]
+
+if env['TARGET_PLATFORM'] == 'MAC':
+ INPUTS += [
+ 'aggregator-mac.mm',
+ 'const-mac.mm',
+ 'uploader_aggregation-mac.mm',
+ 'uploader-mac.mm',
+ ]
+
+if env['TARGET_PLATFORM'] == 'POSIX':
+ INPUTS += [
+ 'uploader-posix.cc',
+ ]
+
+# Build a library called 'o3dStatsreport' from the input sources.
+lib = env.ComponentLibrary('o3dStatsreport', INPUTS)
diff --git a/o3d/statsreport/common/build.scons b/o3d/statsreport/common/build.scons
new file mode 100644
index 0000000..489e911
--- /dev/null
+++ b/o3d/statsreport/common/build.scons
@@ -0,0 +1,53 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Import('env')
+
+env.Append(
+ LIBPATH=[
+ '$LIBS_DIR'
+ ],
+ LIBS = ['o3d_base']
+)
+
+INPUTS = []
+
+if env['TARGET_PLATFORM'] == 'WINDOWS':
+ INPUTS += [
+ 'highres_timer-win32.cc',
+ ]
+
+if env['TARGET_PLATFORM'] == 'MAC':
+ INPUTS += [
+ 'highres_timer-mac.cc',
+ ]
+
+# Build a library called 'o3dStatsreport_Common' from the input sources.
+env.ComponentLibrary('o3dStatsreport_Common', INPUTS)
diff --git a/o3d/statsreport/common/const_product.h b/o3d/statsreport/common/const_product.h
new file mode 100644
index 0000000..ef4f624
--- /dev/null
+++ b/o3d/statsreport/common/const_product.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Product-specific constants.
+//
+
+#ifndef O3D_STATSREPORT_COMMON_CONST_PRODUCT_H_
+#define O3D_STATSREPORT_COMMON_CONST_PRODUCT_H_
+
+#include <build/build_config.h>
+#include "base/basictypes.h"
+
+#define _QUOTEME(x) #x
+#define QUOTEME(x) _QUOTEME(x)
+
+#define _WIDEN(X) L ## X
+#define WIDEN(X) _WIDEN(X)
+
+#define PRODUCT_NAME_STRING "o3d"
+#define PRODUCT_VERSION_STRING QUOTEME(O3D_VERSION_NUMBER)
+
+#define PRODUCT_NAME_STRING_WIDE WIDEN(PRODUCT_NAME_STRING)
+
+// keep these two in sync
+#define REGISTRY_KEY_NAME_STRING "o3d"
+#define REGISTRY_KEY_STRING "Software\\Google\\O3D"
+
+#ifdef OS_WIN
+const char kMetricsLockName[] = PRODUCT_NAME_STRING "MetricsAggregationlock";
+#endif
+
+const char kProductName[] = PRODUCT_NAME_STRING;
+
+// TODO: Determine if #define below is needed.
+// This is a string value to be found under they key
+// at REGISTRY_KEY_STRING. This is written by our
+// installer
+// #define INSTALL_DIR_VALUE_NAME "InstallDir"
+
+const char kUserAgent[] = "O3D-";
+
+const int kStatsUploadIntervalSec = 24 * 60 * 60; // once per day
+const int kStatsAggregationIntervalMSec = 5 * 60 * 1000; // every 5 minutes
+
+// Taken from Google Update
+// TODO: CRITICAL: Link to actual Google Update docs so that we don't have
+// to keep this up to date. It will mess with our logs.
+const wchar_t* const kRegValueUserId = L"ui";
+const wchar_t* const kRelativeGoopdateRegPath = L"Software\\Google\\Update\\";
+
+const wchar_t* const kClientstateRegistryKey =
+ L"Software\\Google\\Update\\ClientState\\"
+ L"{70308795-045C-42DA-8F4E-D452381A7459}";
+const wchar_t* const kOptInRegistryKey = L"usagestats";
+
+#define INTERNET_MAX_PATH_LENGTH 2048
+#define INTERNET_MAX_SCHEME_LENGTH 32
+#define INTERNET_MAX_URL_LENGTH (INTERNET_MAX_SCHEME_LENGTH \
+ + sizeof("://") \
+ + INTERNET_MAX_PATH_LENGTH)
+
+#endif // O3D_STATSREPORT_COMMON_CONST_PRODUCT_H_
diff --git a/o3d/statsreport/common/highres_timer-linux.cc b/o3d/statsreport/common/highres_timer-linux.cc
new file mode 100644
index 0000000..d577fc3
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-linux.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/common/highres_timer.h"
+
+const uint64 MICROS_IN_MILLI = 1000L;
+const uint64 MICROS_IN_HALF_MILLI = 500L;
+const uint64 MICROS_IN_HALF_SECOND = 500000L;
+
+uint64 HighresTimer::GetElapsedMs() const {
+ uint64 end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearest ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ return (static_cast<uint64>(end_time - start_ticks_) +
+ MICROS_IN_HALF_MILLI) /
+ MICROS_IN_MILLI;
+}
+
+uint64 HighresTimer::GetElapsedSec() const {
+ uint64 end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearest ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ return (static_cast<uint64>(end_time - start_ticks_) +
+ MICROS_IN_HALF_SECOND) /
+ MICROS_IN_SECOND;
+}
diff --git a/o3d/statsreport/common/highres_timer-linux.h b/o3d/statsreport/common/highres_timer-linux.h
new file mode 100644
index 0000000..7574a8f
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-linux.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_STATSREPORT_COMMON_HIGHRES_TIMER_LINUX_H_
+#define O3D_STATSREPORT_COMMON_HIGHRES_TIMER_LINUX_H_
+
+#include "base/basictypes.h"
+
+#include <sys/time.h>
+
+const uint64 MICROS_IN_SECOND = 1000000L;
+
+// A handy class for reliably measuring wall-clock time with decent resolution.
+//
+// We want to measure time with high resolution on Linux. What to do?
+//
+// RDTSC? Sure, but how do you convert it to wall clock time?
+// clock_gettime? It's not in all Linuxes.
+//
+// Let's just use gettimeofday; it's good to the microsecond.
+class HighresTimer {
+ public:
+ // Captures the current start time
+ HighresTimer();
+
+ // Captures the current tick, can be used to reset a timer for reuse.
+ void Start();
+
+ // Returns the elapsed ticks with full resolution
+ uint64 GetElapsedTicks() const;
+
+ // Returns the elapsed time in milliseconds, rounded to the nearest
+ // millisecond.
+ uint64 GetElapsedMs() const;
+
+ // Returns the elapsed time in seconds, rounded to the nearest second.
+ uint64 GetElapsedSec() const;
+
+ uint64 start_ticks() const { return start_ticks_; }
+
+ // Returns timer frequency from cache, should be less
+ // overhead than ::QueryPerformanceFrequency
+ static uint64 GetTimerFrequency();
+ // Returns current ticks
+ static uint64 GetCurrentTicks();
+
+ private:
+ // Captured start time
+ uint64 start_ticks_;
+};
+
+inline HighresTimer::HighresTimer() {
+ Start();
+}
+
+inline void HighresTimer::Start() {
+ start_ticks_ = GetCurrentTicks();
+}
+
+inline uint64 HighresTimer::GetTimerFrequency() {
+ // fixed; one "tick" is one microsecond
+
+ return MICROS_IN_SECOND;
+}
+
+inline uint64 HighresTimer::GetCurrentTicks() {
+ timeval tv;
+ (void)gettimeofday(&tv, 0);
+
+ return tv.tv_sec * MICROS_IN_SECOND + tv.tv_usec;
+}
+
+inline uint64 HighresTimer::GetElapsedTicks() const {
+ return start_ticks_ - GetCurrentTicks();
+}
+
+#endif // O3D_STATSREPORT_COMMON_HIGHRES_TIMER_LINUX_H_
diff --git a/o3d/statsreport/common/highres_timer-mac.cc b/o3d/statsreport/common/highres_timer-mac.cc
new file mode 100644
index 0000000..aa14525
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-mac.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/common/highres_timer.h"
+
+bool HighresTimer::perf_ratio_collected_ = false;
+mach_timebase_info_data_t HighresTimer::perf_ratio_ = {0};
+
+const uint64 NANOS_IN_MILLI = 1000000L;
+const uint64 NANOS_IN_HALF_MILLI = 500000L;
+const uint64 NANOS_IN_SECOND = 1000000000L;
+const uint64 NANOS_IN_HALF_SECOND = 500000000L;
+
+uint64 HighresTimer::GetElapsedMs() const {
+ uint64 end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearest ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ (void)GetTimerFrequency();
+ return (static_cast<uint64>(end_time - start_ticks_) * perf_ratio_.numer +
+ NANOS_IN_HALF_MILLI * perf_ratio_.denom) /
+ (NANOS_IN_MILLI * perf_ratio_.denom);
+}
+
+uint64 HighresTimer::GetElapsedSec() const {
+ uint64 end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearest ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ (void)GetTimerFrequency();
+ return (static_cast<uint64>(end_time - start_ticks_) * perf_ratio_.numer +
+ NANOS_IN_HALF_SECOND * perf_ratio_.denom) /
+ (NANOS_IN_SECOND * perf_ratio_.denom);
+}
+
+void HighresTimer::CollectPerfRatio() {
+ mach_timebase_info(&perf_ratio_);
+ perf_ratio_collected_ = true;
+}
diff --git a/o3d/statsreport/common/highres_timer-mac.h b/o3d/statsreport/common/highres_timer-mac.h
new file mode 100644
index 0000000..af512ac
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-mac.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_STATSREPORT_COMMON_HIGHRES_TIMER_MAC_H_
+#define O3D_STATSREPORT_COMMON_HIGHRES_TIMER_MAC_H_
+
+#include "base/basictypes.h"
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+// A handy class for reliably measuring wall-clock time with decent resolution.
+class HighresTimer {
+ public:
+ // Captures the current start time
+ HighresTimer();
+
+ // Captures the current tick, can be used to reset a timer for reuse.
+ void Start();
+
+ // Returns the elapsed ticks with full resolution
+ uint64 GetElapsedTicks() const;
+
+ // Returns the elapsed time in milliseconds, rounded to the nearest
+ // millisecond.
+ uint64 GetElapsedMs() const;
+
+ // Returns the elapsed time in seconds, rounded to the nearest second.
+ uint64 GetElapsedSec() const;
+
+ uint64 start_ticks() const { return start_ticks_; }
+
+ // Returns timer frequency from cache, should be less
+ // overhead than ::QueryPerformanceFrequency
+ static uint64 GetTimerFrequency();
+ // Returns current ticks
+ static uint64 GetCurrentTicks();
+
+ private:
+ static void CollectPerfRatio();
+
+ // Captured start time
+ uint64 start_ticks_;
+
+ // Captured performance counter frequency
+ static bool perf_ratio_collected_;
+ static mach_timebase_info_data_t perf_ratio_;
+};
+
+inline HighresTimer::HighresTimer() {
+ Start();
+}
+
+inline void HighresTimer::Start() {
+ start_ticks_ = GetCurrentTicks();
+}
+
+inline uint64 HighresTimer::GetTimerFrequency() {
+ if (!perf_ratio_collected_)
+ CollectPerfRatio();
+ // we're losing precision by doing the division here, but this value is only
+ // used to estimate tick time by the unit tests, so we're ok
+ return static_cast<uint64>(perf_ratio_.denom) * 1000000000ULL
+ / perf_ratio_.numer;
+}
+
+inline uint64 HighresTimer::GetCurrentTicks() {
+ return mach_absolute_time();
+}
+
+inline uint64 HighresTimer::GetElapsedTicks() const {
+ return start_ticks_ - GetCurrentTicks();
+}
+
+#endif // O3D_STATSREPORT_COMMON_HIGHRES_TIMER_MAC_H_
diff --git a/o3d/statsreport/common/highres_timer-win32.cc b/o3d/statsreport/common/highres_timer-win32.cc
new file mode 100644
index 0000000..878b237
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-win32.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/common/highres_timer.h"
+
+bool HighresTimer::perf_freq_collected_ = false;
+ULONGLONG HighresTimer::perf_freq_ = 0;
+
+ULONGLONG HighresTimer::GetElapsedMs() const {
+ ULONGLONG end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearerst ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ // Given infinite resolution, this expression could be written as:
+ // trunc((end - start (units:freq*sec))/freq (units:sec) *
+ // 1000 (unit:ms) + 1/2 (unit:ms))
+ ULONGLONG freq = GetTimerFrequency();
+ return ((end_time - start_ticks_) * 1000L + freq / 2) / freq;
+}
+
+ULONGLONG HighresTimer::GetElapsedSec() const {
+ ULONGLONG end_time = GetCurrentTicks();
+
+ // Scale to ms and round to nearerst ms - rounding is important
+ // because otherwise the truncation error may accumulate e.g. in sums.
+ //
+ // Given infinite resolution, this expression could be written as:
+ // trunc((end - start (units:freq*sec))/freq (unit:sec) + 1/2 (unit:sec))
+ ULONGLONG freq = GetTimerFrequency();
+ return ((end_time - start_ticks_) + freq / 2) / freq;
+}
+
+void HighresTimer::CollectPerfFreq() {
+ LARGE_INTEGER freq;
+
+ // Note that this is racy. It's OK, however, because even
+ // concurrent executions of this are idempotent.
+ if (::QueryPerformanceFrequency(&freq)) {
+ perf_freq_ = freq.QuadPart;
+ perf_freq_collected_ = true;
+ }
+}
diff --git a/o3d/statsreport/common/highres_timer-win32.h b/o3d/statsreport/common/highres_timer-win32.h
new file mode 100644
index 0000000..378fdeb
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer-win32.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_STATSREPORT_COMMON_HIGHRES_TIMER_WIN32_H_
+#define O3D_STATSREPORT_COMMON_HIGHRES_TIMER_WIN32_H_
+
+#include <windows.h>
+
+// A handy class for reliably measuring wall-clock time with decent resolution,
+// even on multi-processor machines and on laptops (where RDTSC potentially
+// returns different results on different processors and/or the RDTSC timer
+// clocks at different rates depending on the power state of the CPU,
+// respectively).
+class HighresTimer {
+ public:
+ // Captures the current start time
+ HighresTimer();
+ virtual ~HighresTimer() {}
+
+ // Captures the current tick, can be used to reset a timer for reuse.
+ void Start();
+
+ // Returns the elapsed ticks with full resolution
+ ULONGLONG GetElapsedTicks() const;
+
+ // Returns the elapsed time in milliseconds, rounded to the nearest
+ // millisecond.
+ virtual ULONGLONG GetElapsedMs() const;
+
+ // Returns the elapsed time in seconds, rounded to the nearest second.
+ virtual ULONGLONG GetElapsedSec() const;
+
+ ULONGLONG start_ticks() const { return start_ticks_; }
+
+ // Returns timer frequency from cache, should be less
+ // overhead than ::QueryPerformanceFrequency
+ static ULONGLONG GetTimerFrequency();
+ // Returns current ticks
+ static ULONGLONG GetCurrentTicks();
+
+ private:
+ static void CollectPerfFreq();
+
+ // Captured start time
+ ULONGLONG start_ticks_;
+
+ // Captured performance counter frequency
+ static bool perf_freq_collected_;
+ static ULONGLONG perf_freq_;
+};
+
+inline HighresTimer::HighresTimer() {
+ Start();
+}
+
+inline void HighresTimer::Start() {
+ start_ticks_ = GetCurrentTicks();
+}
+
+inline ULONGLONG HighresTimer::GetTimerFrequency() {
+ if (!perf_freq_collected_)
+ CollectPerfFreq();
+ return perf_freq_;
+}
+
+inline ULONGLONG HighresTimer::GetCurrentTicks() {
+ LARGE_INTEGER ticks;
+ ::QueryPerformanceCounter(&ticks);
+ return ticks.QuadPart;
+}
+
+inline ULONGLONG HighresTimer::GetElapsedTicks() const {
+ return start_ticks_ - GetCurrentTicks();
+}
+
+#endif // O3D_STATSREPORT_COMMON_HIGHRES_TIMER_WIN32_H_
diff --git a/o3d/statsreport/common/highres_timer.h b/o3d/statsreport/common/highres_timer.h
new file mode 100644
index 0000000..5842729
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <build/build_config.h>
+#if defined(OS_WIN)
+#include "statsreport/common/highres_timer-win32.h"
+#elif defined(OS_MACOSX)
+#include "statsreport/common/highres_timer-mac.h"
+#else
+#include "statsreport/common/highres_timer-linux.h"
+#endif
diff --git a/o3d/statsreport/common/highres_timer_unittest.cc b/o3d/statsreport/common/highres_timer_unittest.cc
new file mode 100644
index 0000000..7f40f10
--- /dev/null
+++ b/o3d/statsreport/common/highres_timer_unittest.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "statsreport/common/highres_timer.h"
+#include "gtest/gtest.h"
+#include "base/basictypes.h"
+
+// These unittests have proven to be flaky on the build server. While
+// we don't want them breaking the build, we still build them to guard
+// against bitrot. On dev's machines during local builds we leave them
+// enabled.
+#ifndef BUILD_SERVER_BUILD
+TEST(HighresTimer, MillisecondClock) {
+#else
+TEST(HighresTimer, DISABLED_MillisecondClock) {
+#endif
+ HighresTimer timer;
+
+ // note: this could fail if we context switch between initializing the timer
+ // and here. Very unlikely however.
+ EXPECT_EQ(0, timer.GetElapsedMs());
+ timer.Start();
+ uint64 half_ms = HighresTimer::GetTimerFrequency() / 2000;
+ // busy wait for half a millisecond
+ while (timer.start_ticks() + half_ms > HighresTimer::GetCurrentTicks()) {
+ // Nothing
+ }
+ EXPECT_EQ(1, timer.GetElapsedMs());
+}
+
+#ifndef BUILD_SERVER_BUILD
+TEST(HighresTimer, SecondClock) {
+#else
+TEST(HighresTimer, DISABLED_SecondClock) {
+#endif
+ HighresTimer timer;
+
+ EXPECT_EQ(0, timer.GetElapsedSec());
+#ifdef OS_WIN
+ ::Sleep(250);
+#else
+ struct timespec ts1 = {0, 250000000};
+ nanosleep(&ts1, 0);
+#endif
+ EXPECT_EQ(0, timer.GetElapsedSec());
+ EXPECT_LE(230, timer.GetElapsedMs());
+ EXPECT_GE(270, timer.GetElapsedMs());
+#ifdef OS_WIN
+ ::Sleep(251);
+#else
+ struct timespec ts2 = {0, 251000000};
+ nanosleep(&ts2, 0);
+#endif
+ EXPECT_EQ(1, timer.GetElapsedSec());
+}
diff --git a/o3d/statsreport/const-mac.h b/o3d/statsreport/const-mac.h
new file mode 100644
index 0000000..9cc2746
--- /dev/null
+++ b/o3d/statsreport/const-mac.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Mac stats aggregation and uploading
+#ifndef O3D_STATSREPORT_CONST_MAC_H__
+#define O3D_STATSREPORT_CONST_MAC_H__
+
+#include <string>
+#import <Cocoa/Cocoa.h>
+
+namespace stats_report {
+
+extern const std::string kCountsKeyName;
+extern const std::string kTimingsKeyName;
+extern const std::string kIntegersKeyName;
+extern const std::string kBooleansKeyName;
+
+#define kLastTransmissionTimeValueName @"LastTransmission"
+NSString* O3DStatsPath(void);
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_CONST_MAC_H__
diff --git a/o3d/statsreport/const-mac.mm b/o3d/statsreport/const-mac.mm
new file mode 100644
index 0000000..d8e9bca
--- /dev/null
+++ b/o3d/statsreport/const-mac.mm
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Posix stats aggregation and uploading
+#include "const-mac.h"
+
+namespace stats_report {
+
+const std::string kTimingsKeyName("Timings");
+const std::string kCountsKeyName("Counts");
+const std::string kIntegersKeyName("Integers");
+const std::string kBooleansKeyName("Booleans");
+
+
+static NSString* FindGoogleAppDirectory(void) {
+ NSString *applicationSupportFolder =
+ [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
+ NSUserDomainMask,
+ YES) objectAtIndex:0];
+
+ NSString *googleAppSupportPath =
+ [applicationSupportFolder stringByAppendingString:@"/Google"];
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:googleAppSupportPath])
+ [[NSFileManager defaultManager] createDirectoryAtPath:googleAppSupportPath
+ attributes:nil];
+
+ return googleAppSupportPath;
+}
+
+NSString* O3DStatsPath(void) {
+ static NSString* the_path = NULL;
+ if (!the_path) {
+ the_path = [FindGoogleAppDirectory() stringByAppendingString:@"/O3D_Stats"];
+ [the_path retain];
+ }
+ return the_path;
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/const-posix.cc b/o3d/statsreport/const-posix.cc
new file mode 100644
index 0000000..534468b
--- /dev/null
+++ b/o3d/statsreport/const-posix.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Posix stats aggregation and uploading
+#include "const-posix.h"
+
+namespace stats_report {
+
+const std::string kTimingsKeyName("Timings");
+const std::string kCountsKeyName("Counts");
+const std::string kIntegersKeyName("Integers");
+const std::string kBooleansKeyName("Booleans");
+const std::string kLastTransmissionTimeValueName("LastTransmission");
+
+} // namespace stats_report
diff --git a/o3d/statsreport/const-posix.h b/o3d/statsreport/const-posix.h
new file mode 100644
index 0000000..271d531
--- /dev/null
+++ b/o3d/statsreport/const-posix.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Posix stats aggregation and uploading
+#ifndef O3D_STATSREPORT_CONST_POSIX_H__
+#define O3D_STATSREPORT_CONST_POSIX_H__
+
+#include <string>
+
+namespace stats_report {
+
+extern const std::string kCountsKeyName;
+extern const std::string kTimingsKeyName;
+extern const std::string kIntegersKeyName;
+extern const std::string kBooleansKeyName;
+extern const std::string kLastTransmissionTimeValueName;
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_CONST_POSIX_H__
diff --git a/o3d/statsreport/const-win32.cc b/o3d/statsreport/const-win32.cc
new file mode 100644
index 0000000..a4f3b23
--- /dev/null
+++ b/o3d/statsreport/const-win32.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Win32 stats aggregation and uploading
+#include "const-win32.h"
+
+namespace stats_report {
+
+const wchar_t kTimingsKeyName[] = L"Timings";
+const wchar_t kCountsKeyName[] = L"Counts";
+const wchar_t kIntegersKeyName[] = L"Integers";
+const wchar_t kBooleansKeyName[] = L"Booleans";
+const wchar_t kStatsKeyFormatString[] = L"Software\\Google\\"
+ L"%ws\\UsageStats\\Daily";
+const wchar_t kLastTransmissionTimeValueName[] = L"LastTransmission";
+
+} // namespace stats_report
diff --git a/o3d/statsreport/const-win32.h b/o3d/statsreport/const-win32.h
new file mode 100644
index 0000000..a4897411
--- /dev/null
+++ b/o3d/statsreport/const-win32.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Constants for Win32 stats aggregation and uploading
+#ifndef O3D_STATSREPORT_CONST_WIN32_H__
+#define O3D_STATSREPORT_CONST_WIN32_H__
+
+namespace stats_report {
+
+extern const wchar_t kCountsKeyName[];
+extern const wchar_t kTimingsKeyName[];
+extern const wchar_t kIntegersKeyName[];
+extern const wchar_t kBooleansKeyName[];
+extern const wchar_t kStatsKeyFormatString[];
+extern const wchar_t kLastTransmissionTimeValueName[];
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_CONST_WIN32_H__
diff --git a/o3d/statsreport/const_server.h b/o3d/statsreport/const_server.h
new file mode 100644
index 0000000..1443486
--- /dev/null
+++ b/o3d/statsreport/const_server.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Product-specific constants for uploading.
+//
+
+#ifndef O3D_STATSREPORT_INTERNAL_CONST_SERVER_H_
+#define O3D_STATSREPORT_INTERNAL_CONST_SERVER_H_
+
+#include <build/build_config.h>
+#include "base/basictypes.h"
+
+
+// Metrics reporting server constants
+#define METRICS_SERVER_NAME "www.google.com"
+#define METRICS_SERVER_PORT 80
+#define METRICS_SERVER_PATH "tbproxy/usagestats"
+
+#define METRICS_TESTING_SERVER_NAME "0.usagestats.server.toolbar-team.eh.borg.google.com";
+#define METRICS_TESTING_SERVER_PORT 25510
+
+const char kStatsServerParamSourceId[] = "sourceid";
+const char kStatsServerParamVersion[] = "v";
+
+#endif // O3D_STATSREPORT_INTERNAL_CONST_SERVER_H_
diff --git a/o3d/statsreport/formatter.cc b/o3d/statsreport/formatter.cc
new file mode 100644
index 0000000..f295b25
--- /dev/null
+++ b/o3d/statsreport/formatter.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "formatter.h"
+
+namespace stats_report {
+
+Formatter::Formatter(const char *name, uint32 measurement_secs) {
+ output_ << name << "&" << measurement_secs;
+}
+
+Formatter::~Formatter() {
+}
+
+void Formatter::AddCount(const char *name, uint64 value) {
+ output_ << "&" << name << ":c=" << value;
+}
+
+void Formatter::AddTiming(const char *name, uint64 num, uint64 avg,
+ uint64 min, uint64 max) {
+ output_ << "&" << name << ":t=" << num << ";"
+ << avg << ";" << min << ";" << max;
+}
+
+void Formatter::AddInteger(const char *name, uint64 value) {
+ output_ << "&" << name << ":i=" << value;
+}
+
+void Formatter::AddBoolean(const char *name, bool value) {
+ output_ << "&" << name << ":b=" << (value ? "t" : "f");
+}
+
+void Formatter::AddMetric(MetricBase *metric) {
+ switch (metric->type()) {
+ case kCountType: {
+ CountMetric *count = metric->AsCount();
+ AddCount(count->name(), count->value());
+ break;
+ }
+ case kTimingType: {
+ TimingMetric *timing = metric->AsTiming();
+ AddTiming(timing->name(), timing->count(), timing->average(),
+ timing->minimum(), timing->maximum());
+ break;
+ }
+ case kIntegerType: {
+ IntegerMetric *integer = metric->AsInteger();
+ AddInteger(integer->name(), integer->value());
+ break;
+ }
+ case kBoolType: {
+ BoolMetric *boolean = metric->AsBool();
+ // TODO: boolean->value() returns a TristateBoolValue. The
+ // formatter is going to serialize kBoolUnset to true.
+ DCHECK_NE(boolean->value(), BoolMetric::kBoolUnset);
+ AddBoolean(boolean->name(), boolean->value() != BoolMetric::kBoolFalse);
+ break;
+ }
+ default:
+ DCHECK(false && "Impossible metric type");
+ }
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/formatter.h b/o3d/statsreport/formatter.h
new file mode 100644
index 0000000..eab534d
--- /dev/null
+++ b/o3d/statsreport/formatter.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Utility class to format metrics to a string suitable for posting to
+// TB stats server.
+#ifndef O3D_STATSREPORT_FORMATTER_H__
+#define O3D_STATSREPORT_FORMATTER_H__
+
+#include <strstream>
+#include "base/basictypes.h"
+#include "metrics.h"
+
+namespace stats_report {
+
+// A utility class that knows how to turn metrics into a string for
+// reporting to the Toolbar stats server.
+class Formatter {
+ public:
+ // @param name the name of the application to report stats against
+ Formatter(const char *name, uint32 measurement_secs);
+ ~Formatter();
+
+ // Add metric to the output string
+ void AddMetric(MetricBase *metric);
+
+ // Add typed metrics to the output string
+ // @{
+ void AddCount(const char *name, uint64 value);
+ void AddTiming(const char *name, uint64 num, uint64 avg, uint64 min,
+ uint64 max);
+ void AddInteger(const char *name, uint64 value);
+ void AddBoolean(const char *name, bool value);
+ // @}
+
+ // Terminates the output string and returns it.
+ // It is an error to add metrics after output() is called.
+ const char *output() {
+ output_ << std::ends;
+ return output_.str();
+ }
+
+ private:
+ mutable std::strstream output_;
+
+ DISALLOW_COPY_AND_ASSIGN(Formatter);
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_FORMATTER_H__
diff --git a/o3d/statsreport/formatter_unittest.cc b/o3d/statsreport/formatter_unittest.cc
new file mode 100644
index 0000000..6567efd
--- /dev/null
+++ b/o3d/statsreport/formatter_unittest.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "gtest/gtest.h"
+#include "formatter.h"
+
+using stats_report::Formatter;
+
+TEST(Formatter, Format) {
+ Formatter formatter("test_application", 86400);
+
+ formatter.AddCount("count1", 10);
+ formatter.AddTiming("timing1", 2, 150, 50, 200);
+ formatter.AddInteger("integer1", 3000);
+ formatter.AddBoolean("boolean1", true);
+ formatter.AddBoolean("boolean2", false);
+
+ EXPECT_STREQ("test_application&86400"
+ "&count1:c=10"
+ "&timing1:t=2;150;50;200"
+ "&integer1:i=3000"
+ "&boolean1:b=t"
+ "&boolean2:b=f",
+ formatter.output());
+}
diff --git a/o3d/statsreport/lock.h b/o3d/statsreport/lock.h
new file mode 100644
index 0000000..23d4a14
--- /dev/null
+++ b/o3d/statsreport/lock.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Declaration of LLock, the lock implementation we use.
+#ifndef O3D_STATSREPORT_LOCK_H_
+#define O3D_STATSREPORT_LOCK_H_
+
+#include <windows.h>
+
+namespace stats_report {
+
+class LLock {
+ public:
+ LLock() {
+ InitializeCriticalSection(&lock_);
+ }
+ ~LLock() {
+ DeleteCriticalSection(&lock_);
+ };
+
+ void Lock() {
+ EnterCriticalSection(&lock_);
+ }
+ void Unlock() {
+ LeaveCriticalSection(&lock_);
+ }
+
+ private:
+ CRITICAL_SECTION lock_;
+};
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_LOCK_H_
diff --git a/o3d/statsreport/metrics.cc b/o3d/statsreport/metrics.cc
new file mode 100644
index 0000000..17dc3a1
--- /dev/null
+++ b/o3d/statsreport/metrics.cc
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Implements metrics and metrics collections
+#include "metrics.h"
+
+#ifndef OS_WIN
+#include <pthread.h>
+#else // OS_WIN
+#include "lock.h"
+#endif // OS_WIN
+
+namespace stats_report {
+// Make sure global stats collection is placed in zeroed storage so as to avoid
+// initialization order snafus.
+MetricCollectionBase g_global_metric_storage = { 0, 0 };
+MetricCollection &g_global_metrics =
+ *static_cast<MetricCollection*>(&g_global_metric_storage);
+
+#pragma warning(push)
+// C4640: construction of local static object is not thread-safe.
+// C4073: initializers put in library initialization area.
+#pragma warning(disable : 4640 4073)
+
+// Serialize all metric manipulation and access under this lock.
+#ifdef OS_WIN
+// Initializes g_lock before other global objects of user defined types.
+// It assumes the program is single threaded while executing CRT startup and
+// exit code.
+#pragma init_seg(lib)
+LLock g_lock;
+#pragma warning(pop)
+#else // OS_WIN
+// On non-Windowsen we use a link time initialized pthread mutex.
+pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif // OS_WIN
+
+class MetricBase::ObjectLock {
+ public:
+ explicit ObjectLock(const MetricBase *metric) : metric_(metric) {
+ metric_->Lock();
+ }
+
+ ~ObjectLock() {
+ metric_->Unlock();
+ }
+
+ private:
+ MetricBase const *const metric_;
+ DISALLOW_COPY_AND_ASSIGN(ObjectLock);
+};
+
+void MetricBase::Lock() const {
+#ifdef OS_WIN
+ g_lock.Lock();
+#else // OS_WIN
+ pthread_mutex_lock(&g_lock);
+#endif // OS_WIN
+}
+
+void MetricBase::Unlock() const {
+#ifdef OS_WIN
+ g_lock.Unlock();
+#else // OS_WIN
+ pthread_mutex_unlock(&g_lock);
+#endif // OS_WIN
+}
+
+MetricBase::MetricBase(const char *name,
+ MetricType type,
+ MetricCollectionBase *coll)
+ : name_(name), type_(type), next_(coll->first_), coll_(coll) {
+ DCHECK_NE(static_cast<MetricCollectionBase*>(NULL), coll_);
+ DCHECK_EQ(false, coll_->initialized_);
+ coll->first_ = this;
+}
+
+MetricBase::MetricBase(const char *name, MetricType type)
+ : name_(name), type_(type), next_(NULL), coll_(NULL) {
+}
+
+MetricBase::~MetricBase() {
+ if (coll_) {
+ DCHECK_EQ(this, coll_->first_);
+ LOG_IF(WARNING, coll_->initialized_)
+ << "Warning: Metric destructor called without call to Uninitialize().";
+
+ coll_->first_ = next_;
+ } else {
+ DCHECK(NULL == next_);
+ }
+}
+
+void IntegerMetricBase::Set(uint64 value) {
+ ObjectLock lock(this);
+ value_ = value;
+}
+
+uint64 IntegerMetricBase::value() const {
+ ObjectLock lock(this);
+ uint64 ret = value_;
+ return ret;
+}
+
+void IntegerMetricBase::Increment() {
+ ObjectLock lock(this);
+ ++value_;
+}
+
+void IntegerMetricBase::Decrement() {
+ ObjectLock lock(this);
+ --value_;
+}
+
+void IntegerMetricBase::Add(uint64 value) {
+ ObjectLock lock(this);
+ value_ += value;
+}
+
+void IntegerMetricBase::Subtract(uint64 value) {
+ ObjectLock lock(this);
+ if (value_ < value)
+ value_ = 0;
+ else
+ value_ -= value;
+}
+
+uint64 CountMetric::Reset() {
+ ObjectLock lock(this);
+ uint64 ret = value_;
+ value_ = 0;
+ return ret;
+}
+
+TimingMetric::TimingData TimingMetric::Reset() {
+ ObjectLock lock(this);
+ TimingData ret = data_;
+ Clear();
+ return ret;
+}
+
+uint32 TimingMetric::count() const {
+ ObjectLock lock(this);
+ uint32 ret = data_.count;
+ return ret;
+}
+
+uint64 TimingMetric::sum() const {
+ ObjectLock lock(this);
+ uint64 ret = data_.sum;
+ return ret;
+}
+
+uint64 TimingMetric::minimum() const {
+ ObjectLock lock(this);
+ uint64 ret = data_.minimum;
+ return ret;
+}
+
+uint64 TimingMetric::maximum() const {
+ ObjectLock lock(this);
+ uint64 ret = data_.maximum;
+ return ret;
+}
+
+uint64 TimingMetric::average() const {
+ ObjectLock lock(this);
+
+ uint64 ret = 0;
+ if (0 == data_.count) {
+ DCHECK_EQ(0, data_.sum);
+ } else {
+ ret = data_.sum / data_.count;
+ }
+ return ret;
+}
+
+void TimingMetric::AddSample(uint64 time_ms) {
+ ObjectLock lock(this);
+ if (0 == data_.count) {
+ data_.minimum = time_ms;
+ data_.maximum = time_ms;
+ } else {
+ if (data_.minimum > time_ms)
+ data_.minimum = time_ms;
+ if (data_.maximum < time_ms)
+ data_.maximum = time_ms;
+ }
+ data_.count++;
+ data_.sum += time_ms;
+}
+
+void TimingMetric::AddSamples(uint64 count, uint64 total_time_ms) {
+ if (0 == count)
+ return;
+
+ uint64 time_ms = total_time_ms / count;
+
+ ObjectLock lock(this);
+ if (0 == data_.count) {
+ data_.minimum = time_ms;
+ data_.maximum = time_ms;
+ } else {
+ if (data_.minimum > time_ms)
+ data_.minimum = time_ms;
+ if (data_.maximum < time_ms)
+ data_.maximum = time_ms;
+ }
+
+ // TODO: truncation from 64 to 32 may occur here.
+ DCHECK_LE(count, kuint32max);
+ data_.count += static_cast<uint32>(count);
+ data_.sum += total_time_ms;
+}
+
+void TimingMetric::Clear() {
+ memset(&data_, 0, sizeof(data_));
+}
+
+void BoolMetric::Set(bool value) {
+ ObjectLock lock(this);
+ value_ = value ? kBoolTrue : kBoolFalse;
+}
+
+BoolMetric::TristateBoolValue BoolMetric::Reset() {
+ ObjectLock lock(this);
+ TristateBoolValue ret = value_;
+ value_ = kBoolUnset;
+ return ret;
+}
+
+void MetricCollection::Initialize() {
+ DCHECK(!initialized());
+ initialized_ = true;
+}
+
+void MetricCollection::Uninitialize() {
+ DCHECK(initialized());
+ initialized_ = false;
+}
+
+
+} // namespace stats_report
diff --git a/o3d/statsreport/metrics.h b/o3d/statsreport/metrics.h
new file mode 100644
index 0000000..876b29c
--- /dev/null
+++ b/o3d/statsreport/metrics.h
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Declares the interface to in-memory metrics capture
+#ifndef O3D_STATSREPORT_METRICS_H__
+#define O3D_STATSREPORT_METRICS_H__
+
+#include <iterator>
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "statsreport/common/highres_timer.h"
+
+// Macros to declare & define named & typed metrics.
+// Put declarations in headers or in cpp files, where you need access
+// to the metrics. For each declared metric, there must be precisely
+// one definition in a compilation unit someplace.
+
+// A count metric should be used to report anything that monotonically
+// increases.
+// Examples:
+// # event count
+// how often does this condition hit, this function get called
+// # aggregate sums
+// how many bytes are written
+#define DECLARE_METRIC_count(name) DECLARE_METRIC(CountMetric, name)
+#define DEFINE_METRIC_count(name) DEFINE_METRIC(CountMetric, name)
+
+// Use timing metrics to report on the performance of important things.
+// A timing metric will report the count of occurrences, as well as the
+// average, min and max times.
+// Samples are measured in milliseconds if you use the TIME_SCOPE macro
+// or the HighResTimer class to collect samples.
+#define DECLARE_METRIC_timing(name) DECLARE_METRIC(TimingMetric, name)
+#define DEFINE_METRIC_timing(name) DEFINE_METRIC(TimingMetric, name)
+
+// Collects a sample from here to the end of the current scope, and
+// adds the sample to the timing metric supplied
+#define TIME_SCOPE(timing) \
+ stats_report::TimingSample __xxsample__(&timing)
+
+// Use integer metrics to report runtime values that fluctuate.
+// Examples:
+// # object count
+// How many objects of some type exist
+// # disk space or memory
+// How much disk space or memory is in use
+#define DECLARE_METRIC_integer(name) DECLARE_METRIC(IntegerMetric, name)
+#define DEFINE_METRIC_integer(name) DEFINE_METRIC(IntegerMetric, name)
+
+
+// Use boolean metrics to report the occurrence of important but rare events
+// or conditions. Note that a boolean metric is tri-state, so you typically
+// want to set it only in one direction, and typically to true.
+// Setting a boolean metric one way or another on a trigger event will report
+// the setting of the boolean immediately prior to reporting, which is
+// typically not what you want.
+#define DECLARE_METRIC_bool(name) DECLARE_METRIC(BoolMetric, name)
+#define DEFINE_METRIC_bool(name) DEFINE_METRIC(BoolMetric, name)
+
+
+// Implementation macros
+#define DECLARE_METRIC(type, name) \
+ namespace o3d_statsreport { \
+ extern stats_report::type metric_##name; \
+ } \
+ using o3d_statsreport::metric_##name
+
+#define DEFINE_METRIC(type, name) \
+ namespace o3d_statsreport { \
+ stats_report::type metric_##name(#name, \
+ &stats_report::g_global_metric_storage); \
+ } \
+ using o3d_statsreport::metric_##name
+
+
+namespace stats_report {
+
+enum MetricType {
+ // use zero for invalid, because global storage defaults to zero
+ kInvalidType = 0,
+ kCountType,
+ kTimingType,
+ kIntegerType,
+ kBoolType
+};
+
+// fwd.
+struct MetricCollectionBase;
+class MetricCollection;
+class MetricBase;
+class IntegerMetricBase;
+class CountMetric;
+class TimingMetric;
+class IntegerMetric;
+class BoolMetric;
+
+// Base class for all stats instances.
+// Stats instances are chained together against a MetricCollection to
+// allow enumerating stats.
+//
+// MetricCollection is factored into a class to make it easier to unittest
+// the implementation.
+class MetricBase {
+ public:
+ // @name Safe downcasts
+ // @{
+ CountMetric *AsCount();
+ TimingMetric *AsTiming();
+ IntegerMetric *AsInteger();
+ BoolMetric *AsBool();
+
+ const CountMetric *AsCount() const;
+ const TimingMetric *AsTiming() const;
+ const IntegerMetric *AsInteger() const;
+ const BoolMetric *AsBool() const;
+ // @}
+
+ // @name Accessors
+ // @{
+ MetricType type() const { return type_; }
+ MetricBase *next() const { return next_; }
+ const char *name() const { return name_; }
+ // @}
+
+ // TODO: does this need to be virtual?
+ virtual ~MetricBase() = 0;
+
+ protected:
+ class ObjectLock;
+ void Lock() const;
+ void Unlock() const;
+
+ // Constructs a MetricBase and adds to the provided MetricCollection.
+ // @note Metrics can only be constructed up to the point where the
+ // MetricCollection is initialized, and there's no locking performed.
+ // The assumption is that outside unit tests, Metrics will we declared
+ // as static/global variables, and initialized at static initialization
+ // time - and static initialization is single-threaded.
+ MetricBase(const char *name, MetricType type, MetricCollectionBase *coll);
+
+ // Constructs a named typed MetricBase
+ MetricBase(const char *name, MetricType type);
+
+ // Our name
+ char const *const name_;
+
+ // type of this metric
+ MetricType const type_;
+
+ // chains to next stat instance
+ MetricBase *const next_;
+
+ // The collection we're created against
+ MetricCollectionBase *const coll_;
+
+ private:
+ template <class SubType>
+ SubType *SafeCast() {
+ return SubType::kType == type() ? static_cast<SubType*>(this) : NULL;
+ }
+ template <class SubType>
+ const SubType *SafeCast() const {
+ return SubType::kType == type() ? static_cast<const SubType*>(this) : NULL;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MetricBase);
+};
+
+// Must be a POD
+struct MetricCollectionBase {
+ bool initialized_;
+ MetricBase *first_;
+};
+
+// Inherit from base, which is a POD and can be initialized at link time.
+//
+// The global MetricCollection is aliased to a link-time initialized
+// instance of MetricCollectionBase, and must not extend the size of its
+// base class.
+class MetricCollection: public MetricCollectionBase {
+ public:
+ MetricCollection() {
+ initialized_ = false;
+ first_ = NULL;
+ }
+ ~MetricCollection() {
+ DCHECK(NULL == first_);
+ }
+
+ // Initialize must be called after all metrics have been added to the
+ // collection, but before enumerating it for e.g. aggregation or reporting.
+ // The intent is that outside unit tests, there will only be the global
+ // metrics collection, which will accrue all metrics defined with the
+ // DEFINE_METRIC_* macros.
+ // Typically you'd call Initialize very early in your main function, and
+ // Uninitialize towards the end of main.
+ // It is an error to Initialize() when the collection is initialized().
+ void Initialize();
+
+ // Uninitialize must be called before removing (deleting or deconstructing)
+ // metrics from the collection.
+ // It is an error to Uninitialize() when the collection is !initialized().
+ void Uninitialize();
+
+ MetricBase *first() const { return first_; }
+ bool initialized() const { return initialized_; }
+
+ private:
+ using MetricCollectionBase::initialized_;
+ using MetricCollectionBase::first_;
+
+ // MetricBase is intimate with us
+ friend class MetricBase;
+
+ DISALLOW_COPY_AND_ASSIGN(MetricCollection);
+};
+
+// Implements a forward_iterator for MetricCollection.
+class MetricIterator: public std::iterator<std::forward_iterator_tag,
+ MetricBase *> {
+ public:
+ MetricIterator() : curr_(NULL) {
+ }
+ // We need a non-explicit copy constructor to satisfy the iterator interface.
+ MetricIterator(const MetricIterator &other) : curr_(other.curr_) {
+ }
+ explicit MetricIterator(const MetricCollection &coll) : curr_(coll.first()) {
+ DCHECK(coll.initialized());
+ }
+
+ MetricBase *operator*() const {
+ return curr_;
+ }
+ MetricBase *operator->() const {
+ return curr_;
+ }
+ MetricIterator operator++() { // preincrement
+ if (curr_)
+ curr_ = curr_->next();
+
+ return *this;
+ }
+ MetricIterator operator++(int dummy) { // postincrement
+ MetricIterator ret(*this);
+ ++*this;
+ return ret;
+ }
+
+ private:
+ MetricBase *curr_;
+};
+
+inline bool operator == (const MetricIterator &a, const MetricIterator &b) {
+ return *a == *b;
+}
+inline bool operator != (const MetricIterator &a, const MetricIterator &b) {
+ return !operator == (a, b);
+}
+
+// Globally defined counters are registered here
+extern MetricCollectionBase g_global_metric_storage;
+
+// And more conveniently accessed through here
+extern MetricCollection &g_global_metrics;
+
+// Base class for integer metrics
+class IntegerMetricBase: public MetricBase {
+ public:
+ // Sets the current value
+ void Set(uint64 value);
+
+ // Retrieves the current value
+ uint64 value() const;
+
+ void operator ++() { Increment(); }
+ void operator ++(int dummy) { Increment(); }
+ void operator +=(uint64 addend) { Add(addend); }
+
+ protected:
+ IntegerMetricBase(const char *name,
+ MetricType type,
+ MetricCollectionBase *coll)
+ : MetricBase(name, type, coll), value_(0) {
+ }
+ IntegerMetricBase(const char *name, MetricType type, uint64 value)
+ : MetricBase(name, type), value_(value) {
+ }
+
+ void Increment();
+ void Decrement();
+ void Add(uint64 value);
+ void Subtract(uint64 value);
+
+ uint64 value_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IntegerMetricBase);
+};
+
+// A count metric is a cumulative counter of events.
+class CountMetric: public IntegerMetricBase {
+ public:
+ // Our type.
+ static const int kType = kCountType;
+
+ CountMetric(const char *name, MetricCollectionBase *coll)
+ : IntegerMetricBase(name, kCountType, coll) {
+ }
+
+ CountMetric(const char *name, uint64 value)
+ : IntegerMetricBase(name, kCountType, value) {
+ }
+
+ // Nulls the metric and returns the current values.
+ uint64 Reset();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CountMetric);
+};
+
+class TimingMetric: public MetricBase {
+ public:
+ static const int kType = kTimingType;
+
+ struct TimingData {
+ uint32 count;
+ uint32 align; // allow access to the alignment gap between count and sum,
+ // makes it easier to unittest.
+ uint64 sum; // ms
+ uint64 minimum; // ms
+ uint64 maximum; // ms
+ };
+
+ TimingMetric(const char *name, MetricCollectionBase *coll)
+ : MetricBase(name, kTimingType, coll) {
+ Clear();
+ }
+
+ TimingMetric(const char *name, const TimingData &value)
+ : MetricBase(name, kTimingType), data_(value) {
+ }
+
+ uint32 count() const;
+ uint64 sum() const;
+ uint64 minimum() const;
+ uint64 maximum() const;
+ uint64 average() const;
+
+ // Adds a single sample to the metric
+ // @param time_ms time (in milliseconds) for this sample
+ void AddSample(uint64 time_ms);
+
+ // Adds count samples to the metric
+ // @note use this when capturing time over a variable number of items to
+ // normalize e.g. download time per byte or KB. This records one sample
+ // over count items, which is numerically more stable for the average
+ // than dividing the captured time by the item count. As a side benefit
+ // the timer will also record the item count.
+ // @note if count == 0, no sample will be recorded
+ // @param count number of samples to add
+ // @param total_time_ms the total time consumed by all the "count" samples
+ void AddSamples(uint64 count, uint64 total_time_ms);
+
+ // Nulls the metric and returns the current values.
+ TimingData Reset();
+
+ private:
+ void Clear();
+
+ TimingData data_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimingMetric);
+};
+
+// A convenience class to sample the time from construction to destruction
+// against a given timing metric.
+class TimingSample {
+ public:
+ // @param timing the metric the sample is to be tallied against
+ explicit TimingSample(TimingMetric *timing) : timing_(timing), count_(1) {
+ DCHECK(NULL != timing);
+ }
+
+ // @param timing the metric the sample is to be tallied against
+ // @param item_count count of items processed, used to divide the sampled
+ // time so as to capture time per item, which is often a better measure
+ // than the total time over a varying number of items.
+ TimingSample(TimingMetric *timing, uint32 item_count) : timing_(timing),
+ count_(item_count) {
+ DCHECK(NULL != timing);
+ }
+
+ ~TimingSample() {
+ // We discard samples with a zero count
+ if (1 == count_)
+ timing_->AddSample(timer_.GetElapsedMs());
+ else
+ timing_->AddSamples(count_, timer_.GetElapsedMs());
+ }
+
+ // @name Accessors
+ // @{
+ uint32 count() const { return count_; }
+ void set_count(uint32 count) { count_ = count; }
+ // @}
+
+ private:
+ // Collects the sample for us.
+ HighresTimer timer_;
+
+ // The metric we tally against.
+ TimingMetric *timing_;
+
+ // The item count we divide the captured time by
+ uint32 count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TimingSample);
+};
+
+// An integer metric is used to sample values that vary over time.
+// On aggregation the instantaneous value of the integer metric is captured.
+class IntegerMetric: public IntegerMetricBase {
+ public:
+ static const int kType = kIntegerType;
+
+ IntegerMetric(const char *name, MetricCollectionBase *coll)
+ : IntegerMetricBase(name, kIntegerType, coll) {
+ }
+
+ IntegerMetric(const char *name, uint64 value)
+ : IntegerMetricBase(name, kIntegerType, value) {
+ }
+
+ void operator = (uint64 value) { Set(value); }
+
+ void operator --() { Decrement(); }
+ void operator --(int dummy) { Decrement(); }
+ void operator -=(uint64 sub) { Subtract(sub); }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IntegerMetric);
+};
+
+// A bool metric is tri-state, and can be:
+// - unset,
+// - true or
+// - false
+// to match other metrics, which are implicitly unset if they've not changed
+// from their initial value.
+class BoolMetric: public MetricBase {
+ public:
+ static const int kType = kBoolType;
+
+ // Values we can take
+ enum TristateBoolValue {
+ kBoolUnset = -1,
+ kBoolFalse,
+ kBoolTrue,
+ };
+
+ BoolMetric(const char *name, MetricCollectionBase *coll)
+ : MetricBase(name, kBoolType, coll), value_(kBoolUnset) {
+ }
+
+ BoolMetric(const char *name, uint32 value)
+ : MetricBase(name, kBoolType) {
+ switch (value) {
+ case kBoolFalse:
+ case kBoolTrue:
+ value_ = static_cast<TristateBoolValue>(value);
+ break;
+
+ default:
+ DCHECK(false && "Unexpected tristate bool value on construction");
+ value_ = kBoolUnset;
+ }
+ }
+
+ // Sets the flag to the provided value.
+ void Set(bool value);
+
+ void operator = (bool value) {
+ Set(value);
+ }
+
+ // Nulls the metric and returns the current values.
+ TristateBoolValue Reset();
+
+ // Returns the current value - not threadsafe.
+ TristateBoolValue value() const { return value_; }
+
+ private:
+ TristateBoolValue value_;
+
+ DISALLOW_COPY_AND_ASSIGN(BoolMetric);
+};
+
+inline CountMetric *MetricBase::AsCount() {
+ return SafeCast<CountMetric>();
+}
+
+inline TimingMetric *MetricBase::AsTiming() {
+ return SafeCast<TimingMetric>();
+}
+
+inline IntegerMetric *MetricBase::AsInteger() {
+ return SafeCast<IntegerMetric>();
+}
+
+inline BoolMetric *MetricBase::AsBool() {
+ return SafeCast<BoolMetric>();
+}
+
+inline const CountMetric *MetricBase::AsCount() const {
+ return SafeCast<CountMetric>();
+}
+
+inline const TimingMetric *MetricBase::AsTiming() const {
+ return SafeCast<TimingMetric>();
+}
+
+inline const IntegerMetric *MetricBase::AsInteger() const {
+ return SafeCast<IntegerMetric>();
+}
+
+inline const BoolMetric *MetricBase::AsBool() const {
+ return SafeCast<BoolMetric>();
+}
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_METRICS_H__
diff --git a/o3d/statsreport/metrics_unittest.cc b/o3d/statsreport/metrics_unittest.cc
new file mode 100644
index 0000000..db2fe29
--- /dev/null
+++ b/o3d/statsreport/metrics_unittest.cc
@@ -0,0 +1,407 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Metrics report unit testing
+#include <new>
+#include <algorithm>
+#include "gtest/gtest.h"
+#include "metrics.h"
+
+DECLARE_METRIC_count(count);
+DEFINE_METRIC_count(count);
+
+DECLARE_METRIC_timing(timing);
+DEFINE_METRIC_timing(timing);
+
+DECLARE_METRIC_integer(integer);
+DEFINE_METRIC_integer(integer);
+
+DECLARE_METRIC_bool(bool);
+DEFINE_METRIC_bool(bool);
+
+using ::stats_report::BoolMetric;
+using ::stats_report::CountMetric;
+using ::stats_report::IntegerMetric;
+using ::stats_report::MetricBase;
+using ::stats_report::MetricCollection;
+using ::stats_report::MetricCollectionBase;
+using ::stats_report::MetricIterator;
+using ::stats_report::TimingMetric;
+using ::stats_report::TimingSample;
+using ::stats_report::kBoolType;
+using ::stats_report::kCountType;
+using ::stats_report::kIntegerType;
+using ::stats_report::kTimingType;
+
+namespace {
+
+class MetricsTest: public testing::Test {
+ protected:
+ MetricCollection coll_;
+};
+
+class MetricsEnumTest: public MetricsTest {
+ public:
+ virtual void SetUp() {
+ coll_.Initialize();
+ }
+
+ virtual void TearDown() {
+ coll_.Uninitialize();
+ }
+
+ protected:
+ MetricsEnumTest(): count_("count", &coll_), timing_("timing", &coll_),
+ integer_("integer", &coll_), bool_("bool", &coll_) {
+ }
+
+ CountMetric count_;
+ TimingMetric timing_;
+ IntegerMetric integer_;
+ BoolMetric bool_;
+};
+
+} // namespace
+
+// Validates that the above-declared metrics are available
+// in the expected namespace
+TEST_F(MetricsTest, Globals) {
+ EXPECT_EQ(0, ::metric_count.Reset());
+ TimingMetric::TimingData data = ::metric_timing.Reset();
+ EXPECT_EQ(0, data.count);
+ EXPECT_EQ(0, data.maximum);
+ EXPECT_EQ(0, data.minimum);
+ EXPECT_EQ(0, data.sum);
+
+ EXPECT_EQ(0, ::metric_integer.value());
+ EXPECT_EQ(BoolMetric::kBoolUnset, ::metric_bool.Reset());
+
+ // Check for correct initialization
+ EXPECT_STREQ("count", metric_count.name());
+ EXPECT_STREQ("timing", metric_timing.name());
+ EXPECT_STREQ("integer", metric_integer.name());
+ EXPECT_STREQ("bool", metric_bool.name());
+}
+
+
+// make GUnit happy
+inline std::ostream &operator << (std::ostream &str, const MetricIterator &it) {
+ str << std::hex << reinterpret_cast<void*>(*it);
+ return str;
+}
+
+TEST_F(MetricsTest, CollectionInitialization) {
+ // The global MetricCollection is aliased to zero memory so as to ensure
+ // no initialization order snafus. If an initialized MetricCollection
+ // sets any of its storage to non-zero, there's a good chance that e.g. a
+ // vtbl has snuck in there, which must not happen
+ char buf1[sizeof(MetricCollection)] = { 0 };
+ char buf2[sizeof(MetricCollection)] = { 0 };
+
+ // Placement new a MetricCollection to one of the buffers
+ new (buf1) MetricCollection();
+
+ // and check they're still equivalent
+ EXPECT_EQ(0, memcmp(buf1, buf2, sizeof(MetricCollection)));
+
+ // MetricCollection must not extend MetricCollectionBase in size
+ EXPECT_EQ(sizeof(MetricCollection), sizeof(MetricCollectionBase));
+}
+
+TEST_F(MetricsTest, Count) {
+ CountMetric foo("foo", &coll_);
+
+ EXPECT_EQ(0, foo.Reset());
+ EXPECT_EQ(kCountType, foo.type());
+ ASSERT_TRUE(NULL != foo.AsCount());
+ ASSERT_TRUE(NULL == foo.AsTiming());
+ ASSERT_TRUE(NULL == foo.AsInteger());
+ ASSERT_TRUE(NULL == foo.AsBool());
+
+ ++foo;
+ EXPECT_EQ(1, foo.value());
+ foo++;
+ EXPECT_EQ(2, foo.value());
+
+ foo += 100;
+ EXPECT_EQ(102, foo.value());
+}
+
+TEST_F(MetricsTest, Timing) {
+ TimingMetric foo("foo", &coll_);
+
+ EXPECT_EQ(kTimingType, foo.type());
+ ASSERT_TRUE(NULL == foo.AsCount());
+ ASSERT_TRUE(NULL != foo.AsTiming());
+ ASSERT_TRUE(NULL == foo.AsInteger());
+ ASSERT_TRUE(NULL == foo.AsBool());
+
+ foo.AddSample(100);
+ foo.AddSample(50);
+
+ EXPECT_EQ(2, foo.count());
+ EXPECT_EQ(150, foo.sum());
+ EXPECT_EQ(100, foo.maximum());
+ EXPECT_EQ(50, foo.minimum());
+ EXPECT_EQ(75, foo.average());
+
+ TimingMetric::TimingData data = foo.Reset();
+ EXPECT_EQ(2, data.count);
+ EXPECT_EQ(150, data.sum);
+ EXPECT_EQ(100, data.maximum);
+ EXPECT_EQ(50, data.minimum);
+
+ EXPECT_EQ(0, foo.count());
+ EXPECT_EQ(0, foo.sum());
+ EXPECT_EQ(0, foo.maximum());
+ EXPECT_EQ(0, foo.minimum());
+ EXPECT_EQ(0, foo.average());
+
+ // Test counted samples
+ foo.AddSamples(10, 1000);
+ foo.AddSamples(10, 500);
+ EXPECT_EQ(20, foo.count());
+ EXPECT_EQ(1500, foo.sum());
+ EXPECT_EQ(100, foo.maximum());
+ EXPECT_EQ(50, foo.minimum());
+ EXPECT_EQ(75, foo.average());
+}
+
+TEST_F(MetricsTest, TimingSample) {
+ TimingMetric foo("foo", &coll_);
+
+ // add a sample to foo
+ {
+ TimingSample sample(&foo);
+
+ ::Sleep(30);
+ }
+
+ TimingMetric::TimingData data = foo.Reset();
+
+ // Should be precisely one sample in there
+ EXPECT_EQ(1, data.count);
+
+ // Disable flaky tests on build server, unfortunately this reduces coverage
+ // too, but it seems preferrable to breaking the build on a regular basis.
+#ifndef BUILD_SERVER_BUILD
+ // Let's hope the scheduler doesn't leave us hanging more than 10 ms.
+ EXPECT_GT(40, data.sum);
+ // The sleep above seems to often terminate early on the build server,
+ // I've observed captured times down to 18 ms, which is strange.
+ // TODO: figure out whether the timer is broken or whether
+ // sleep is breaking its promise, or whether e.g. we're getting different
+ // walltimes on different CPUs due to BIOS bugs on the build server
+ EXPECT_LT(15, data.sum);
+#endif
+
+ // again, this time with a non-unity count
+ {
+ TimingSample sample(&foo, 2);
+
+ EXPECT_EQ(2, sample.count());
+ ::Sleep(30);
+ }
+
+ data = foo.Reset();
+
+ // Should be precisely two samples in there
+ EXPECT_EQ(2, data.count);
+
+ // Disable flaky tests on build server, unfortunately this reduces coverage
+ // too, but it seems preferrable to breaking the build on a regular basis.
+#ifndef BUILD_SERVER_BUILD
+ // Let's hope the scheduler doesn't leave us hanging more than 10 ms.
+ EXPECT_GT(40, data.sum);
+ EXPECT_LT(15, data.sum);
+#endif
+
+ // now with zero count
+ {
+ TimingSample sample(&foo, 0);
+ }
+
+ data = foo.Reset();
+
+ // Should be no samples in there
+ EXPECT_EQ(0, data.count);
+}
+
+TEST_F(MetricsTest, Integer) {
+ IntegerMetric foo("foo", &coll_);
+
+ EXPECT_EQ(kIntegerType, foo.type());
+ ASSERT_TRUE(NULL == foo.AsCount());
+ ASSERT_TRUE(NULL == foo.AsTiming());
+ ASSERT_TRUE(NULL != foo.AsInteger());
+ ASSERT_TRUE(NULL == foo.AsBool());
+
+ EXPECT_EQ(0, foo.value());
+ foo.Set(1005);
+ EXPECT_EQ(1005, foo.value());
+ foo = 1009UL;
+ EXPECT_EQ(1009, foo.value());
+
+ foo.Set(0);
+
+ ++foo;
+ EXPECT_EQ(1, foo.value());
+ foo++;
+ EXPECT_EQ(2, foo.value());
+
+ foo += 100;
+ EXPECT_EQ(102, foo.value());
+
+ foo -= 100;
+ EXPECT_EQ(2, foo.value());
+ foo--;
+ EXPECT_EQ(1, foo.value());
+ --foo;
+ EXPECT_EQ(0, foo.value());
+}
+
+TEST_F(MetricsTest, Bool) {
+ BoolMetric foo("foo", &coll_);
+
+ EXPECT_EQ(kBoolType, foo.type());
+ ASSERT_TRUE(NULL == foo.AsCount());
+ ASSERT_TRUE(NULL == foo.AsTiming());
+ ASSERT_TRUE(NULL == foo.AsInteger());
+ ASSERT_TRUE(NULL != foo.AsBool());
+
+ EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());
+ foo.Set(true);
+ EXPECT_EQ(BoolMetric::kBoolTrue, foo.Reset());
+ foo.Set(false);
+ EXPECT_EQ(BoolMetric::kBoolFalse, foo.Reset());
+ EXPECT_EQ(BoolMetric::kBoolUnset, foo.Reset());
+}
+
+TEST_F(MetricsEnumTest, Enumeration) {
+ MetricBase *metrics[] = {
+ &count_,
+ &timing_,
+ &integer_,
+ &bool_,
+ };
+
+ for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {
+ MetricBase *stat = metrics[i];
+ MetricBase *curr = coll_.first();
+
+ for (; NULL != curr; curr = curr->next()) {
+ if (stat == curr)
+ break;
+ }
+
+ // if NULL, we didn't find our counter
+ EXPECT_TRUE(NULL != curr);
+ }
+}
+
+TEST_F(MetricsEnumTest, Iterator) {
+ typedef MetricBase *MetricBasePtr;
+ MetricBasePtr metrics[] = { &count_, &timing_, &integer_, &bool_, };
+ int num_stats = arraysize(metrics);
+
+ MetricIterator it(coll_), end;
+ EXPECT_NE(it, end);
+
+ // copy construction
+ EXPECT_EQ(it, MetricIterator(it));
+ EXPECT_EQ(end, MetricIterator(end));
+
+ // # of iterations
+ int i = 0;
+ while (it++ != end)
+ ++i;
+ ASSERT_EQ(num_stats, i);
+ ASSERT_EQ(end, it);
+
+ // increment past end is idempotent
+ ++it;
+ ASSERT_EQ(end, it);
+
+ // Check that we return no garbage or nonsense
+ for (it = MetricIterator(coll_); it != end; ++it) {
+ MetricBasePtr *stats_end = &metrics[num_stats];
+ EXPECT_NE(stats_end, std::find(metrics, stats_end, *it));
+ }
+
+ // and that all metrics can be found
+ for (int i = 0; i < sizeof(metrics) / sizeof(metrics[0]); ++i) {
+ MetricBase *stat = metrics[i];
+
+ EXPECT_EQ(stat, *std::find(MetricIterator(coll_), end, stat));
+ }
+}
+
+TEST_F(MetricsTest, SimpleConstruction) {
+ const CountMetric c("c", 100);
+
+ EXPECT_EQ(100, c.value());
+ EXPECT_EQ(kCountType, c.type());
+ EXPECT_STREQ("c", c.name());
+ EXPECT_TRUE(NULL == c.next());
+
+ TimingMetric::TimingData data = { 10, 0, 1000, 10, 500 };
+ const TimingMetric t("t", data);
+
+ EXPECT_EQ(10, t.count());
+ EXPECT_EQ(1000, t.sum());
+ EXPECT_EQ(10, t.minimum());
+ EXPECT_EQ(500, t.maximum());
+ EXPECT_EQ(kTimingType, t.type());
+ EXPECT_STREQ("t", t.name());
+ EXPECT_TRUE(NULL == t.next());
+
+ const IntegerMetric i("i", 200);
+
+ EXPECT_EQ(200, i.value());
+ EXPECT_EQ(kIntegerType, i.type());
+ EXPECT_STREQ("i", i.name());
+ EXPECT_TRUE(NULL == i.next());
+
+ const BoolMetric bool_true("bool_true", BoolMetric::kBoolTrue);
+
+ EXPECT_EQ(BoolMetric::kBoolTrue, bool_true.value());
+ EXPECT_EQ(kBoolType, bool_true.type());
+ EXPECT_STREQ("bool_true", bool_true.name());
+ EXPECT_TRUE(NULL == bool_true.next());
+
+ const BoolMetric bool_false("bool_false", BoolMetric::kBoolFalse);
+
+ EXPECT_EQ(BoolMetric::kBoolFalse, bool_false.value());
+ EXPECT_EQ(kBoolType, bool_false.type());
+ EXPECT_STREQ("bool_false", bool_false.name());
+ EXPECT_TRUE(NULL == bool_false.next());
+}
diff --git a/o3d/statsreport/persistent_iterator-win32.cc b/o3d/statsreport/persistent_iterator-win32.cc
new file mode 100644
index 0000000..edf687b
--- /dev/null
+++ b/o3d/statsreport/persistent_iterator-win32.cc
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Iterator over persisted metrics
+#include "persistent_iterator-win32.h"
+
+namespace stats_report {
+
+void PersistentMetricsIteratorWin32::Next() {
+ current_value_.reset();
+
+ // Try to open the top-level key if we didn't already.
+ if (NULL == key_.m_hKey) {
+ HKEY parent_key = is_machine_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ LONG err = key_.Open(parent_key, key_name_, KEY_READ);
+ if (err != ERROR_SUCCESS)
+ return;
+ }
+
+ // Loop until we find a value
+ while (state_ != kFinished) {
+ if (NULL == sub_key_.m_hKey) {
+ const wchar_t *subkey_name = NULL;
+ switch (state_) {
+ case kUninitialized:
+ state_ = kCounts;
+ subkey_name = kCountsKeyName;
+ break;
+ case kCounts:
+ state_ = kTimings;
+ subkey_name = kTimingsKeyName;
+ break;
+ case kTimings:
+ state_ = kIntegers;
+ subkey_name = kIntegersKeyName;
+ break;
+ case kIntegers:
+ state_ = kBooleans;
+ subkey_name = kBooleansKeyName;
+ break;
+ case kBooleans:
+ state_ = kFinished;
+ break;
+ case kFinished:
+ break;
+ }
+
+ if (NULL != subkey_name) {
+ LONG err = sub_key_.Open(key_, subkey_name, KEY_READ);
+ // go around the loop on error to try the next key type
+ if (ERROR_SUCCESS != err)
+ continue;
+ }
+
+ // reset value enumeration
+ value_index_ = 0;
+ }
+
+ if (state_ != kFinished) {
+ DCHECK(NULL != sub_key_.m_hKey);
+ CString wide_value_name;
+ DWORD value_name_len = 255;
+ DWORD value_type = 0;
+ BYTE buf[sizeof(TimingMetric::TimingData)];
+ DWORD value_len = sizeof(buf);
+
+ // Get the next key and value
+ LONG err = ::RegEnumValue(sub_key_,
+ value_index_,
+ CStrBuf(wide_value_name, value_name_len),
+ &value_name_len,
+ 0,
+ &value_type,
+ buf,
+ &value_len);
+
+ ++value_index_;
+
+ if (ERROR_NO_MORE_ITEMS == err) {
+ // done with this subkey, go around again
+ sub_key_.Close();
+ continue;
+ } else if (ERROR_SUCCESS != err) {
+ // some other error, broken into a separate case for ease of debugging
+ DCHECK(false && "Unexpected error during reg value enumeration");
+ } else {
+ DCHECK(ERROR_SUCCESS == err);
+
+ // convert value to ASCII
+ current_value_name_ = wide_value_name;
+
+ switch (state_) {
+ case kCounts:
+ if (value_len != sizeof(uint64))
+ continue;
+ current_value_.reset(
+ new CountMetric(current_value_name_ .GetString(),
+ *reinterpret_cast<uint64*>(&buf[0])));
+ break;
+ case kTimings:
+ if (value_len != sizeof(TimingMetric::TimingData))
+ continue;
+ current_value_.reset(
+ new TimingMetric(
+ current_value_name_.GetString(),
+ *reinterpret_cast<TimingMetric::TimingData*>(&buf[0])));
+ break;
+ case kIntegers:
+ if (value_len != sizeof(uint64))
+ continue;
+ current_value_.reset(new IntegerMetric(
+ current_value_name_.GetString(),
+ *reinterpret_cast<uint64*>(&buf[0])));
+ break;
+ case kBooleans:
+ if (value_len != sizeof(uint32))
+ continue;
+ current_value_.reset(
+ new BoolMetric(current_value_name_.GetString(),
+ *reinterpret_cast<uint32*>(&buf[0])));
+ break;
+ default:
+ DCHECK(false && "Impossible state during reg value enumeration");
+ break;
+ }
+
+ if (current_value_.get())
+ return;
+ }
+ }
+ }
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/persistent_iterator-win32.h b/o3d/statsreport/persistent_iterator-win32.h
new file mode 100644
index 0000000..ceaf851
--- /dev/null
+++ b/o3d/statsreport/persistent_iterator-win32.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Iterator over persisted metrics
+#ifndef O3D_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
+#define O3D_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
+
+#include <atlbase.h>
+#include <atlstr.h>
+#include <iterator>
+#include "base/scoped_ptr.h"
+#include "metrics.h"
+#include "const-win32.h"
+
+namespace stats_report {
+
+// Forward iterator for persisted metrics
+class PersistentMetricsIteratorWin32
+ : public std::iterator<std::forward_iterator_tag, const MetricBase *> {
+ public:
+ // @param app_name see MetricsAggregatorWin32
+ explicit PersistentMetricsIteratorWin32(const wchar_t *app_name)
+ : state_(kUninitialized),
+ is_machine_(false) {
+ key_name_.Format(kStatsKeyFormatString, app_name);
+ Next();
+ }
+
+ // @param app_name see MetricsAggregatorWin32
+ // @param is_machine specifies the registry hive
+ PersistentMetricsIteratorWin32(const wchar_t *app_name, bool is_machine)
+ : state_(kUninitialized),
+ is_machine_(is_machine) {
+ key_name_.Format(kStatsKeyFormatString, app_name);
+ Next();
+ }
+
+ // Constructs the at-end iterator
+ PersistentMetricsIteratorWin32() : state_(kUninitialized) {
+ }
+
+ MetricBase *operator* () {
+ return Current();
+ }
+ MetricBase *operator-> () {
+ return Current();
+ }
+
+ // Preincrement, we don't implement postincrement because we don't
+ // want to deal with making iterators copyable, comparable etc.
+ PersistentMetricsIteratorWin32 &operator++() {
+ Next();
+
+ return (*this);
+ }
+
+ // Compare for equality with o.
+ bool equals(const PersistentMetricsIteratorWin32 &o) const {
+ // compare equal to self, and end iterators compare equal
+ if ((this == &o) || (NULL == current_value_.get() &&
+ NULL == o.current_value_.get()))
+ return true;
+
+ return false;
+ }
+
+ private:
+ MetricBase *Current() {
+ DCHECK(current_value_.get());
+ return current_value_.get();
+ }
+
+ enum IterationState {
+ kUninitialized,
+ kCounts,
+ kTimings,
+ kIntegers,
+ kBooleans,
+ kFinished,
+ };
+
+ // Walk to the next key/value under iteration
+ void Next();
+
+ // Keeps track of which subkey we're iterating over
+ IterationState state_;
+
+ // The full path from HKCU to the key we iterate over
+ CString key_name_;
+
+ // The top-level key we're iterating over, valid only
+ // after first call to Next().
+ CRegKey key_;
+
+ // The subkey we're currently enumerating over
+ CRegKey sub_key_;
+
+ // Current value we're indexing over
+ DWORD value_index_;
+
+ // Name of the value under the iterator
+ CStringA current_value_name_;
+
+ // The metric under the iterator
+ scoped_ptr<MetricBase> current_value_;
+
+ // Specifies HKLM or HKCU, respectively.
+ bool is_machine_;
+};
+
+inline bool operator == (const PersistentMetricsIteratorWin32 &a,
+ const PersistentMetricsIteratorWin32 &b) {
+ return a.equals(b);
+}
+
+inline bool operator != (const PersistentMetricsIteratorWin32 &a,
+ const PersistentMetricsIteratorWin32 &b) {
+ return !a.equals(b);
+}
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_PERSISTENT_ITERATOR_WIN32_H__
diff --git a/o3d/statsreport/persistent_iterator-win32_unittest.cc b/o3d/statsreport/persistent_iterator-win32_unittest.cc
new file mode 100644
index 0000000..69e6f55
--- /dev/null
+++ b/o3d/statsreport/persistent_iterator-win32_unittest.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <iterator>
+#include <map>
+#include "gtest/gtest.h"
+#include "const-win32.h"
+#include "aggregator-win32_unittest.h"
+#include "persistent_iterator-win32.h"
+
+using ::stats_report::BoolMetric;
+using ::stats_report::CountMetric;
+using ::stats_report::IntegerMetric;
+using ::stats_report::MetricBase;
+using ::stats_report::MetricCollection;
+using ::stats_report::MetricCollectionBase;
+using ::stats_report::MetricIterator;
+using ::stats_report::MetricsAggregatorWin32;
+using ::stats_report::PersistentMetricsIteratorWin32;
+using ::stats_report::TimingMetric;
+using ::stats_report::TimingSample;
+using ::stats_report::kBoolType;
+using ::stats_report::kCountType;
+using ::stats_report::kIntegerType;
+using ::stats_report::kInvalidType;
+using ::stats_report::kTimingType;
+
+namespace {
+
+class PersistentMetricsIteratorWin32Test: public MetricsAggregatorWin32Test {
+ public:
+ bool WriteStats() {
+ // put some persistent metrics into the registry
+ MetricsAggregatorWin32 agg(coll_, kAppName);
+ AddStats();
+ bool ret = agg.AggregateMetrics();
+
+ // Reset the stats, we should now have the same stats
+ // in our collection as in registry.
+ AddStats();
+
+ return ret;
+ }
+
+ typedef std::map<std::string, MetricBase*> MetricsMap;
+ void IndexMetrics(MetricsMap *metrics) {
+ // build a map over the metrics in our collection
+ MetricIterator it(coll_), end;
+
+ for (; it != end; ++it) {
+ metrics->insert(std::make_pair(std::string(it->name()), *it));
+ }
+ }
+};
+
+// compare two metrics instances for equality
+bool equals(MetricBase *a, MetricBase *b) {
+ if (!a || !b)
+ return false;
+
+ if (a->type() != b->type() || 0 != strcmp(a->name(), b->name()))
+ return false;
+
+ switch (a->type()) {
+ case kCountType:
+ return a->AsCount()->value() == b->AsCount()->value();
+ break;
+ case kTimingType: {
+ TimingMetric *at = a->AsTiming();
+ TimingMetric *bt = b->AsTiming();
+
+ return at->count() == bt->count() &&
+ at->sum() == bt->sum() &&
+ at->minimum() == bt->minimum() &&
+ at->maximum() == bt->maximum();
+ break;
+ }
+ case kIntegerType:
+ return a->AsInteger()->value() == b->AsInteger()->value();
+ break;
+ case kBoolType:
+ return a->AsBool()->value() == b->AsBool()->value();
+ break;
+ case kInvalidType:
+ default:
+ LOG(FATAL) << "Impossible metric type";
+ }
+
+ return false;
+}
+
+} // namespace
+
+TEST_F(PersistentMetricsIteratorWin32Test, Basic) {
+ EXPECT_TRUE(WriteStats());
+ PersistentMetricsIteratorWin32 a;
+ PersistentMetricsIteratorWin32 b;
+ PersistentMetricsIteratorWin32 c(kAppName);
+
+ EXPECT_TRUE(a == b);
+ EXPECT_TRUE(b == a);
+
+ EXPECT_FALSE(a == c);
+ EXPECT_FALSE(b == c);
+ EXPECT_FALSE(c == a);
+ EXPECT_FALSE(c == b);
+
+ ++a;
+ EXPECT_TRUE(a == b);
+ EXPECT_TRUE(b == a);
+}
+
+// Test to see whether we can reliably roundtrip metrics through
+// the registry without molestation
+TEST_F(PersistentMetricsIteratorWin32Test, UnmolestedValues) {
+ EXPECT_TRUE(WriteStats());
+
+ MetricsMap metrics;
+ IndexMetrics(&metrics);
+
+ PersistentMetricsIteratorWin32 it(kAppName), end;
+ int count = 0;
+ for (; it != end; ++it) {
+ MetricsMap::iterator found = metrics.find(it->name());
+
+ // make sure we found it, and that it's unmolested in value
+ EXPECT_TRUE(found != metrics.end() && equals(found->second, *it));
+ count++;
+ }
+
+ // Did we visit all metrics?
+ EXPECT_EQ(count, metrics.size());
+}
diff --git a/o3d/statsreport/uploader-mac.mm b/o3d/statsreport/uploader-mac.mm
new file mode 100644
index 0000000..803b800
--- /dev/null
+++ b/o3d/statsreport/uploader-mac.mm
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+
+#import <Cocoa/Cocoa.h>
+#include "base/logging.h"
+
+#include "statsreport/uploader.h"
+#include "statsreport/aggregator-mac.h"
+#include "statsreport/const-mac.h"
+#include "statsreport/formatter.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/const_server.h"
+
+const float kTimeOutInterval = 10.0;
+
+namespace stats_report {
+ // TODO: Refactor to avoid cross platform code duplication.
+
+bool UploadMetrics(const char* extra_url_data, const char* user_agent,
+ const char *content) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+
+ // TODO: refactor to where there's a platform-independent HTTP
+ // interface to the ConnectionManager and pass it through into here.
+ DLOG(INFO) << "Uploading metrics . . . ";
+
+ NSString *url_string =
+ [NSString stringWithFormat:@"http://%s:%d/%s?%s=%s&%s=%s&%s",
+ METRICS_SERVER_NAME,
+ METRICS_SERVER_PORT,
+ METRICS_SERVER_PATH,
+ kStatsServerParamSourceId,
+ PRODUCT_NAME_STRING,
+ kStatsServerParamVersion,
+ PRODUCT_VERSION_STRING,
+ extra_url_data];
+ DLOG(INFO) << "Url: " << [url_string UTF8String];
+
+ NSURL *url = [NSURL URLWithString:url_string];
+
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
+
+ // don't send cookies or user-identifiable info with our request.
+ [request setHTTPShouldHandleCookies:NO];
+ [request setTimeoutInterval:kTimeOutInterval];
+ int content_len = (content == NULL) ? 0 : strlen(content);
+ if (content_len) {
+ NSData *content_data = [NSData dataWithBytesNoCopy:(void*)content
+ length:content_len];
+ [request setHTTPMethod:@"POST"];
+ [request setHTTPBody:content_data];
+ }
+ NSURLResponse *response = nil;
+ NSError *error = nil;
+
+ [NSURLConnection sendSynchronousRequest:request
+ returningResponse:&response
+ error:&error];
+
+ [pool release];
+
+ return (error == nil);
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/uploader-posix.cc b/o3d/statsreport/uploader-posix.cc
new file mode 100644
index 0000000..7275b81
--- /dev/null
+++ b/o3d/statsreport/uploader-posix.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+#include "backend/serverconnectionmanager.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/const_server.h"
+#include "iobuffer/iobuffer-inl.h"
+#include "statsreport/aggregator-posix-inl.h"
+#include "statsreport/const-posix.h"
+#include "statsreport/formatter.h"
+#include "statsreport/uploader.h"
+
+
+DECLARE_int32(metrics_aggregation_interval);
+DECLARE_int32(metrics_upload_interval);
+DECLARE_string(metrics_server_name);
+DECLARE_int32(metrics_server_port);
+
+using stats_report::Formatter;
+using stats_report::MetricsAggregatorPosix;
+
+namespace {
+
+bool UploadMetrics(const char* extra_url_data, const char* user_agent,
+ const char *content) {
+ o3d_transfer_service::ServerConnectionManager scm(
+ METRICS_SERVER_NAME,
+ METRICS_SERVER_PORT,
+ false,
+ PRODUCT_VERSION_STRING,
+ PRODUCT_NAME_STRING);
+
+ PathString path = PathString("/" METRICS_SERVER_PATH "?") +
+ kStatsServerParamSourceId + "=" +
+ PRODUCT_NAME_STRING + "&" +
+ kStatsServerParamVersion + "=" +
+ PRODUCT_VERSION_STRING + "&" +
+ extra_url_data;
+
+ IOBuffer buffer_out;
+ o3d_transfer_service::HttpResponse response;
+ return scm.SimplePost(path, const_cast<char *>(content),
+ strlen(content), &buffer_out, &response);
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/uploader-win32.cc b/o3d/statsreport/uploader-win32.cc
new file mode 100644
index 0000000..ba08e53
--- /dev/null
+++ b/o3d/statsreport/uploader-win32.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlsafe.h>
+#include <time.h>
+#include "base/logging.h"
+
+#include "statsreport/uploader.h"
+#include "statsreport/aggregator-win32.h"
+#include "statsreport/const-win32.h"
+#include "statsreport/persistent_iterator-win32.h"
+#include "statsreport/formatter.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/const_server.h"
+
+namespace stats_report {
+// TODO: Refactor to avoid cross platform code duplication.
+
+bool UploadMetrics(const char* extra_url_data, const char* user_agent,
+ const char *content) {
+ // TODO: refactor to where there's a platform-independent HTTP
+ // interface to the ConnectionManager and pass it through into here.
+ DLOG(INFO) << "Uploading metrics . . . ";
+ CString url;
+ url.Format(L"http://%hs:%d/%hs?%hs=%hs&%hs=%hs&%hs",
+ METRICS_SERVER_NAME,
+ METRICS_SERVER_PORT,
+ METRICS_SERVER_PATH,
+ kStatsServerParamSourceId,
+ PRODUCT_NAME_STRING,
+ kStatsServerParamVersion,
+ PRODUCT_VERSION_STRING,
+ extra_url_data);
+ DLOG(INFO) << "Url: " << url;
+
+ CComPtr<IXMLHttpRequest> request;
+ // create the http request object
+ HRESULT hr = request.CoCreateInstance(CLSID_XMLHTTPRequest);
+ if (FAILED(hr))
+ return false;
+
+ DLOG(INFO) << "Created request.";
+ // open the request
+ // TODO: async?
+ CComVariant empty;
+ CComVariant var_false(false);
+ hr = request->open(CComBSTR("POST"), CComBSTR(url),
+ var_false, empty, empty);
+ if (FAILED(hr))
+ return false;
+ DLOG(INFO) << "Opened request.";
+
+ hr = request->setRequestHeader(CComBSTR("User-Agent"), CComBSTR(user_agent));
+ if (FAILED(hr))
+ DLOG(WARNING) << "Failed to set user-agent";
+
+ // and send the file
+ // TODO: progress?
+ CComSafeArray<BYTE> content_array(strlen(content));
+ hr = request->send(CComVariant(content));
+ if (FAILED(hr))
+ return false;
+ DLOG(INFO) << "Sent content_array.";
+
+#ifndef NDEBUG
+ CComBSTR response;
+ hr = request->get_responseText(&response);
+#endif
+
+ return true;
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/uploader.h b/o3d/statsreport/uploader.h
new file mode 100644
index 0000000..f514171
--- /dev/null
+++ b/o3d/statsreport/uploader.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+#ifndef O3D_STATSREPORT_UPLOADER_H_
+#define O3D_STATSREPORT_UPLOADER_H_
+
+#ifdef OS_WINDOWS
+#include <atlstr.h>
+#endif
+
+#include "statsreport/metrics.h"
+
+namespace stats_report {
+
+class StatsUploader {
+ public:
+ StatsUploader() {}
+ virtual ~StatsUploader() {}
+ virtual bool UploadMetrics(const char* extra_url_data,
+ const char* user_agent,
+ const char *content);
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StatsUploader);
+};
+
+bool AggregateMetrics();
+bool AggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report);
+bool TestableAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report,
+ StatsUploader* stats_uploader);
+bool UploadMetrics(const char* extra_url_data, const char* user_agent,
+ const char *content);
+
+#ifdef OS_WINDOWS
+void ResetPersistentMetrics(CRegKey *key);
+#else
+void ResetPersistentMetrics(void);
+#endif
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_UPLOADER_H_
diff --git a/o3d/statsreport/uploader_aggregation-mac.mm b/o3d/statsreport/uploader_aggregation-mac.mm
new file mode 100644
index 0000000..ff7d86ef
--- /dev/null
+++ b/o3d/statsreport/uploader_aggregation-mac.mm
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+#include "statsreport/aggregator-mac.h"
+#include "statsreport/common/const_product.h"
+#include "statsreport/const-mac.h"
+#include "statsreport/formatter.h"
+#include "statsreport/uploader.h"
+
+
+using stats_report::Formatter;
+using stats_report::MetricsAggregatorMac;
+
+namespace stats_report {
+
+bool AggregateMetrics() {
+ using stats_report::MetricsAggregatorMac;
+ MetricsAggregatorMac aggregator(g_global_metrics);
+ if (!aggregator.AggregateMetrics()) {
+ DLOG(WARNING) << "Metrics aggregation failed for reasons unknown";
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool ReportMetrics(const char* extra_url_data,
+ const char* user_agent,
+ uint32 interval,
+ StatsUploader* stats_uploader) {
+ NSDictionary *dict =
+ [NSDictionary dictionaryWithContentsOfFile:O3DStatsPath()];
+
+ if (dict == nil)
+ return false;
+
+ Formatter formatter(PRODUCT_NAME_STRING, interval);
+ NSArray *keys = [dict allKeys];
+ int count = [keys count];
+
+ for(int x = 0; x < count; ++x) {
+ NSString *name = [keys objectAtIndex:x];
+ NSString *short_name = [name substringFromIndex:2];
+
+ if ([short_name length] == 0)
+ continue;
+
+ const char *short_name_c_str = [short_name UTF8String];
+ id item = [dict objectForKey:name];
+ MetricBase *current = NULL;
+ switch([name characterAtIndex:0]) {
+ case 'C':
+ current = new CountMetric(short_name_c_str,
+ [item longLongValue]);
+ break;
+ case 'B':
+ current = new BoolMetric(short_name_c_str,
+ [item boolValue] == YES);
+ break;
+ case 'T': {
+ TimingMetric::TimingData data;
+ data.count = [[item objectAtIndex:0] intValue];
+ data.sum = [[item objectAtIndex:1] longLongValue];
+ data.minimum = [[item objectAtIndex:2] longLongValue];
+ data.maximum = [[item objectAtIndex:3] longLongValue];
+ current = new TimingMetric(short_name_c_str, data);
+ }
+ break;
+ case 'I':
+ current = new IntegerMetric(short_name_c_str,
+ [item longLongValue]);
+ break;
+ // We don't send this piece of data as it's not a metric.
+ case 'L': // "LastTransmission"
+ break;
+ }
+ if (current != NULL)
+ formatter.AddMetric(current);
+ }
+
+ DLOG(INFO) << "formatter.output() = " << formatter.output();
+ return stats_uploader->UploadMetrics(extra_url_data,
+ user_agent,
+ formatter.output());
+}
+
+void ResetPersistentMetrics() {
+ NSError *error = nil;
+ /*
+ [[NSFileManager defaultManager] removeItemAtPath:O3DStatsPath()
+ error:&error];
+ */
+ [[NSFileManager defaultManager] removeFileAtPath:O3DStatsPath()
+ handler:nil];
+}
+
+
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool AggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report) {
+ StatsUploader stats_uploader;
+ return TestableAggregateAndReportMetrics(extra_url_arguments, user_agent,
+ force_report, &stats_uploader);
+}
+
+static int GetLastTransmissionTime() {
+ NSDictionary *dict =
+ [NSDictionary dictionaryWithContentsOfFile:O3DStatsPath()];
+
+ if (dict == nil)
+ return 0;
+
+ NSNumber *when = [dict objectForKey:kLastTransmissionTimeValueName];
+
+ if (when == nil)
+ return 0;
+
+ return [when intValue];
+}
+
+static void SetLastTransmissionTime(int when) {
+ NSMutableDictionary *dict =
+ [NSMutableDictionary dictionaryWithContentsOfFile:O3DStatsPath()];
+
+ if (dict == nil)
+ dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:when]
+ forKey:kLastTransmissionTimeValueName];
+ else
+ [dict setObject:[NSNumber numberWithInt:when]
+ forKey:kLastTransmissionTimeValueName];
+
+ [dict writeToFile:O3DStatsPath() atomically:YES];
+}
+
+
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool TestableAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report,
+ StatsUploader* stats_uploader) {
+ // Open the store
+ MetricsAggregatorMac aggregator(g_global_metrics);
+
+ int32 now = static_cast<int32>(time(NULL));
+
+ // Retrieve the last transmission time
+ int32 last_transmission_time = GetLastTransmissionTime();
+
+ // if last transmission time is missing or at all dodgy, then
+ // let's wipe all info and start afresh.
+ if (last_transmission_time == 0 || last_transmission_time > now) {
+ LOG(WARNING) << "dodgy or missing last transmission time, wiping stats";
+
+ ResetPersistentMetrics();
+
+ SetLastTransmissionTime(now);
+
+ // Force a report of the stats so we get everything currently in there.
+ force_report = true;
+ }
+
+ if (!AggregateMetrics()) {
+ DLOG(INFO) << "AggregateMetrics returned false";
+ return false;
+ }
+
+ DLOG(INFO) << "Last transmission time: " << last_transmission_time;
+ DLOG(INFO) << "Now: " << now;
+ DLOG(INFO) << "Now - Last transmission time: "
+ << now - last_transmission_time;
+ DLOG(INFO) << "Compared to: " << kStatsUploadIntervalSec;
+
+ // Set last_transmission_time such that it will force
+ // an upload of the metrics
+ if (force_report) {
+ last_transmission_time = now - kStatsUploadIntervalSec;
+ }
+ if (now - last_transmission_time >= kStatsUploadIntervalSec) {
+ bool report_result = ReportMetrics(extra_url_arguments, user_agent,
+ now - last_transmission_time,
+ stats_uploader);
+ if (report_result) {
+ DLOG(INFO) << "Stats upload successful, resetting metrics";
+
+ ResetPersistentMetrics();
+ } else {
+ DLOG(WARNING) << "Stats upload failed";
+ }
+
+ // No matter what, wait another upload interval to try again. It's better
+ // to report older stats than hammer on the stats server exactly when it
+ // has failed.
+ SetLastTransmissionTime(now);
+ return report_result;
+ }
+ return false;
+}
+
+// Used primarily for testing. Default functionality.
+bool StatsUploader::UploadMetrics(const char* extra_url_data,
+ const char* user_agent,
+ const char *content) {
+ return stats_report::UploadMetrics(extra_url_data, user_agent, content);
+}
+
+
+} // namespace stats_report
diff --git a/o3d/statsreport/uploader_aggregation-posix.cc b/o3d/statsreport/uploader_aggregation-posix.cc
new file mode 100644
index 0000000..dca530b
--- /dev/null
+++ b/o3d/statsreport/uploader_aggregation-posix.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+#include "backend/serverconnectionmanager.h"
+#include "statsreport/common/const_product.h"
+#include "iobuffer/iobuffer-inl.h"
+#include "statsreport/aggregator-posix-inl.h"
+#include "statsreport/const-posix.h"
+#include "statsreport/formatter.h"
+#include "statsreport/uploader.h"
+
+
+DECLARE_int32(metrics_aggregation_interval);
+DECLARE_int32(metrics_upload_interval);
+DECLARE_string(metrics_server_name);
+DECLARE_int32(metrics_server_port);
+
+using stats_report::Formatter;
+using stats_report::MetricsAggregatorPosix;
+
+namespace {
+
+bool AggregateMetrics(MetricsAggregatorPosix *aggregator) {
+ if (!aggregator->AggregateMetrics()) {
+ LOG(WARNING) << "Metrics aggregation failed for reasons unknown";
+ return false;
+ }
+
+ return true;
+}
+
+
+bool ReportMetrics(MetricsAggregatorPosix *aggregator,
+ const char* extra_url_data,
+ const char* user_agent,
+ uint32 interval) {
+ Formatter formatter(PRODUCT_NAME_STRING, interval);
+ aggregator->FormatMetrics(&formatter);
+
+ return UploadMetrics(extra_url_data, user_agent, formatter.output());
+}
+
+} // namespace
+
+namespace stats_report {
+
+bool AggregateMetrics() {
+ MetricsAggregatorPosix aggregator(g_global_metrics);
+ return ::AggregateMetrics(&aggregator);
+}
+
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool AggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report) {
+ StatsUploader stats_uploader;
+ return TestableAggregateAndReportMetrics(extra_url_arguments, user_agent,
+ force_report, &stats_uploader);
+}
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool TestableAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report,
+ StatsUploader* stats_uploader) {
+ // Open the store
+ MetricsAggregatorPosix aggregator(g_global_metrics);
+
+ int32 now = static_cast<int32>(time(NULL));
+
+ // Retrieve the last transmission time
+ int32 last_transmission_time;
+ bool success = aggregator.GetValue(kLastTransmissionTimeValueName,
+ &last_transmission_time);
+
+ // if last transmission time is missing or at all hinky, then
+ // let's wipe all info and start afresh.
+ if (!success || last_transmission_time > now) {
+ LOG(WARNING) << "Hinky or missing last transmission time, wiping stats";
+
+ aggregator.ResetMetrics();
+
+ success = aggregator.SetValue(kLastTransmissionTimeValueName, now);
+ if (!success)
+ LOG(ERROR) << "Unable to write last transmission value";
+
+ // we just wiped everything, let's not waste any more time
+ return false;
+ }
+
+ if (!::AggregateMetrics(&aggregator))
+ return false;
+
+ if (now - last_transmission_time >= kStatsUploadInterval) {
+ bool report_result = ReportMetrics(&aggregator, extra_url_arguments,
+ user_agent,
+ now - last_transmission_time);
+ if (report_result) {
+ LOG(INFO) << "Stats upload successful, resetting metrics";
+
+ aggregator.ResetMetrics();
+ } else {
+ LOG(WARNING) << "Stats upload failed";
+ }
+
+ // No matter what, wait another upload interval to try again. It's better
+ // to report older stats than hammer on the stats server exactly when it's
+ // failed.
+ (void)aggregator.SetValue(kLastTransmissionTimeValueName, now);
+ return report_result;
+ }
+ return false;
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/uploader_aggregation-win32.cc b/o3d/statsreport/uploader_aggregation-win32.cc
new file mode 100644
index 0000000..a22dcf3
--- /dev/null
+++ b/o3d/statsreport/uploader_aggregation-win32.cc
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Helper class to manage the process of uploading metrics.
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlsafe.h>
+#include <time.h>
+#include "base/logging.h"
+
+#include "statsreport/uploader.h"
+#include "statsreport/aggregator-win32.h"
+#include "statsreport/const-win32.h"
+#include "statsreport/persistent_iterator-win32.h"
+#include "statsreport/formatter.h"
+#include "statsreport/common/const_product.h"
+
+namespace stats_report {
+// TODO: Refactor to avoid cross platform code duplication.
+
+bool AggregateMetrics() {
+ using stats_report::MetricsAggregatorWin32;
+ MetricsAggregatorWin32 aggregator(g_global_metrics, PRODUCT_NAME_STRING_WIDE);
+ if (!aggregator.AggregateMetrics()) {
+ DLOG(WARNING) << "Metrics aggregation failed for reasons unknown";
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool ReportMetrics(const char* extra_url_data,
+ const char* user_agent,
+ DWORD interval,
+ StatsUploader* stats_uploader) {
+ PersistentMetricsIteratorWin32 it(PRODUCT_NAME_STRING_WIDE), end;
+ Formatter formatter(CStringA(PRODUCT_NAME_STRING), interval);
+
+ for (; it != end; ++it)
+ formatter.AddMetric(*it);
+ DLOG(INFO) << "formatter.output() = " << formatter.output();
+ return stats_uploader->UploadMetrics(extra_url_data, user_agent,
+ formatter.output());
+}
+
+void ResetPersistentMetrics(CRegKey *key) {
+ key->DeleteValue(kLastTransmissionTimeValueName);
+ key->DeleteSubKey(kCountsKeyName);
+ key->DeleteSubKey(kTimingsKeyName);
+ key->DeleteSubKey(kIntegersKeyName);
+ key->DeleteSubKey(kBooleansKeyName);
+}
+
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool AggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report) {
+ StatsUploader stats_uploader;
+ return TestableAggregateAndReportMetrics(extra_url_arguments, user_agent,
+ force_report, &stats_uploader);
+}
+// Returns:
+// true if metrics were uploaded successfully, false otherwise
+// Note: False does not necessarily mean an error, just that no metrics
+// were uploaded
+bool TestableAggregateAndReportMetrics(const char* extra_url_arguments,
+ const char* user_agent,
+ bool force_report,
+ StatsUploader* stats_uploader) {
+ CString key_name;
+ key_name.Format(kStatsKeyFormatString, PRODUCT_NAME_STRING_WIDE);
+
+ CRegKey key;
+ LONG err = key.Create(HKEY_CURRENT_USER, key_name);
+ if (ERROR_SUCCESS != err) {
+ DLOG(WARNING) << "Unable to open metrics key";
+ return false;
+ }
+
+ DWORD now = static_cast<DWORD>(time(NULL));
+
+ // Retrieve the last transmission time
+ DWORD last_transmission_time;
+ DWORD value_type;
+ ULONG value_len = sizeof(last_transmission_time);
+ err = key.QueryValue(kLastTransmissionTimeValueName, &value_type,
+ &last_transmission_time, &value_len);
+
+ // if last transmission time is missing or at all hinky, then
+ // let's wipe all info and start afresh.
+ if (ERROR_SUCCESS != err || REG_DWORD != value_type ||
+ sizeof(last_transmission_time) != value_len ||
+ last_transmission_time > now) {
+ DLOG(WARNING) << "Hinky or missing last transmission time, wiping stats";
+
+ ResetPersistentMetrics(&key);
+
+ err = key.SetValue(kLastTransmissionTimeValueName, REG_DWORD,
+ &now, sizeof(now));
+ if (ERROR_SUCCESS != err) {
+ DLOG(ERROR) << "Unable to write last transmission value, error "
+ << std::hex << err;
+ }
+ // Force a report of the stats so we get everything currently in there.
+ force_report = true;
+
+ // we just wiped everything, let's not waste any more time
+ // return; <-- skipping this since we still want to aggregate
+ }
+
+ if (!AggregateMetrics()) {
+ DLOG(INFO) << "AggregateMetrics returned false";
+ return false;
+ }
+
+ DLOG(INFO) << "Last transimission time: " << last_transmission_time;
+ DLOG(INFO) << "Now: " << now;
+ DLOG(INFO) << "Now - Last transmission time: "
+ << now - last_transmission_time;
+ DLOG(INFO) << "Compared to: " << kStatsUploadIntervalSec;
+
+ // Set last_transmission_time such that it will force
+ // an upload of the metrics
+ if (force_report) {
+ last_transmission_time = now - kStatsUploadIntervalSec;
+ }
+ if (now - last_transmission_time >= kStatsUploadIntervalSec) {
+ bool report_result = ReportMetrics(extra_url_arguments, user_agent,
+ now - last_transmission_time,
+ stats_uploader);
+ if (report_result) {
+ DLOG(INFO) << "Stats upload successful, resetting metrics";
+
+ ResetPersistentMetrics(&key);
+ } else {
+ DLOG(WARNING) << "Stats upload failed";
+ }
+
+ // No matter what, wait another upload interval to try again. It's better
+ // to report older stats than hammer on the stats server exactly when it's
+ // failed.
+ err = key.SetValue(kLastTransmissionTimeValueName, REG_DWORD,
+ &now, sizeof(now));
+ return report_result;
+ }
+ return false;
+}
+
+// Used primarily for testing. Default functionality.
+bool StatsUploader::UploadMetrics(const char* extra_url_data,
+ const char* user_agent,
+ const char *content) {
+ return stats_report::UploadMetrics(extra_url_data, user_agent, content);
+}
+
+} // namespace stats_report
diff --git a/o3d/statsreport/util-win32.h b/o3d/statsreport/util-win32.h
new file mode 100644
index 0000000..f15dfac
--- /dev/null
+++ b/o3d/statsreport/util-win32.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// Utility functions for Win32 stats aggregation and uploading
+#ifndef O3D_STATSREPORT_UTIL_WIN32_H__
+#define O3D_STATSREPORT_UTIL_WIN32_H__
+
+namespace stats_report {
+
+template <class ValueType>
+bool GetData(CRegKey *parent, const wchar_t *value_name, ValueType *value) {
+ ULONG len = sizeof(ValueType);
+ LONG err = parent->QueryBinaryValue(value_name, value, &len);
+ if (ERROR_SUCCESS != err || len != sizeof(ValueType)) {
+ memset(value, 0, sizeof(ValueType));
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace stats_report
+
+#endif // O3D_STATSREPORT_UTIL_WIN32_H__