1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/Runtime/StatsExporter.h"
18#include "glow/Backends/DeviceManager.h"
19#include "glow/Runtime/HostManager/HostManager.h"
20
21#include <gtest/gtest.h>
22
23#include <memory>
24
25using namespace glow;
26
27class MockStatsExporter : public StatsExporter {
28 std::shared_ptr<StatsExporterRegistry> statsExporterRegistry_;
29
30public:
31 MockStatsExporter() : statsExporterRegistry_(StatsExporterRegistry::Stats()) {
32 statsExporterRegistry_->registerStatsExporter(this);
33 }
34
35 ~MockStatsExporter() override {
36 statsExporterRegistry_->revokeStatsExporter(this);
37 }
38
39 void addTimeSeriesValue(llvm::StringRef key, double value) override {
40 timeSeries[key.str()].push_back(value);
41 }
42
43 void incrementCounter(llvm::StringRef key, int64_t value) override {
44 counters[key.str()] += value;
45 }
46
47 void setCounter(llvm::StringRef key, int64_t value) override {
48 counters[key.str()] = value;
49 }
50
51 void clear() {
52 counters.clear();
53 timeSeries.clear();
54 }
55
56 std::map<std::string, int64_t> counters;
57 std::map<std::string, std::vector<double>> timeSeries;
58} MockStats;
59
60class StatsExporterTest : public ::testing::Test {
61 ~StatsExporterTest() { MockStats.clear(); }
62};
63
64TEST(StatsExporter, Counter) {
65 MockStats.setCounter("foo", 1);
66 ASSERT_EQ(MockStats.counters["foo"], 1);
67 MockStats.setCounter("foo", 3);
68 ASSERT_EQ(MockStats.counters["foo"], 3);
69 MockStats.incrementCounter("foo", 1);
70 ASSERT_EQ(MockStats.counters["foo"], 4);
71 MockStats.incrementCounter("foo", -1);
72 ASSERT_EQ(MockStats.counters["foo"], 3);
73}
74
75TEST(StatsExporter, TimeSeries) {
76 MockStats.addTimeSeriesValue("bar", 1);
77 MockStats.addTimeSeriesValue("bar", 3.14);
78 MockStats.addTimeSeriesValue("bar", 2.71);
79 auto it = MockStats.timeSeries.find("bar");
80 ASSERT_NE(it, MockStats.timeSeries.end());
81 auto const &ts = it->second;
82 ASSERT_EQ(ts.size(), 3);
83 EXPECT_EQ(ts[0], 1);
84 EXPECT_EQ(ts[1], 3.14);
85 EXPECT_EQ(ts[2], 2.71);
86}
87
88TEST(StatsExporter, Device) {
89 using namespace glow::runtime;
90 EXPECT_EQ(MockStats.counters.count("glow.devices_used.interpreter"), 0);
91 EXPECT_EQ(MockStats.counters.count("glow.device.used_memory.device0"), 0);
92 EXPECT_EQ(MockStats.counters.count("glow.device.available_memory.device0"),
93 0);
94 {
95 std::unique_ptr<DeviceManager> DM(
96 DeviceManager::createDeviceManager(DeviceConfig("Interpreter")));
97 EXPECT_EQ(MockStats.counters["glow.devices_used.interpreter"], 1);
98 EXPECT_EQ(MockStats.counters["glow.device.used_memory.device0"], 0);
99 EXPECT_EQ(MockStats.counters["glow.device.available_memory.device0"],
100 2000000000);
101 }
102 EXPECT_EQ(MockStats.counters["glow.devices_used.interpreter"], 0);
103}
104
105TEST(StatsExporter, HostManager) {
106 using namespace glow::runtime;
107 EXPECT_EQ(MockStats.counters.count("glow.devices.used_memory.total"), 0);
108 EXPECT_EQ(MockStats.counters.count("glow.devices.available_memory.total"), 0);
109 EXPECT_EQ(MockStats.counters.count("glow.devices.maximum_memory.total"), 0);
110 {
111 auto deviceConfig = glow::make_unique<DeviceConfig>("Interpreter");
112 std::vector<std::unique_ptr<DeviceConfig>> configs;
113 configs.push_back(std::move(deviceConfig));
114 std::unique_ptr<HostManager> HM =
115 glow::make_unique<HostManager>(std::move(configs), HostConfig());
116 EXPECT_EQ(MockStats.counters["glow.devices.used_memory.total"], 0);
117 EXPECT_EQ(MockStats.counters["glow.devices.available_memory.total"],
118 2000000000);
119 EXPECT_EQ(MockStats.counters["glow.devices.maximum_memory.total"],
120 2000000000);
121
122 // Add a network so the memory used value is non-zero.
123 std::unique_ptr<Module> module = glow::make_unique<Module>();
124 Function *F = module->createFunction("main");
125 auto *X = module->createConstant(ElemKind::FloatTy, {1024, 1024}, "X");
126 auto *pow = F->createPow("Pow", X, 2.0);
127 F->createSave("save", pow);
128
129 const int64_t functionCost = X->getType()->getSizeInBytes();
130
131 CompilationContext cctx;
132 EXIT_ON_ERR(HM->addNetwork(std::move(module), cctx));
133 // Currently the interpreter DM treats all added networks as size 1 byte so
134 // expect to see 1 byte used.
135 EXPECT_EQ(MockStats.counters["glow.devices.used_memory.total"],
136 functionCost);
137 EXPECT_EQ(MockStats.counters["glow.devices.available_memory.total"],
138 2000000000 - functionCost);
139 }
140 EXPECT_EQ(MockStats.counters["glow.devices_used.interpreter"], 0);
141}
142