summaryrefslogtreecommitdiffstats
path: root/o3d/statsreport
diff options
context:
space:
mode:
authorgspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
committergspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
commit05b47f7a8c5451f858dc220df0e3a97542edace6 (patch)
treea2273d619f0625c9d44d40842845ccce2eac1045 /o3d/statsreport
parent5cdc8bdb4c847cefe7f4542bd10c9880c2c557a0 (diff)
downloadchromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.zip
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.gz
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.bz2
This is the O3D source tree's initial commit to the Chromium tree. It
is not built or referenced at all by the chrome build yet, and doesn't yet build in it's new home. We'll change that shortly. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
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__