Make memory tests percentage-based
[platform/core/system/stability-monitor.git] / tests / test-stability-mem.cpp
1 #include "test-stability.hpp"
2
3 // C
4 #include <cstdlib>
5
6 // C++
7 #include <fstream>
8 #include <iostream>
9 #include <thread>
10 #include <vector>
11
12 // POSIX
13 #include <sys/sysinfo.h>
14
15 static size_t total_ram_kb; // /proc/meminfo returns in kB
16 static size_t total_ram_b  () { return total_ram_kb * 1024; }
17 static size_t total_ram_mb () { return total_ram_kb / 1024; }
18
19 static void * do_mem (size_t to_alloc)
20 {
21         /* Allocate memory and pretend we're using it (so as to make it actually
22          * count to RSS use). The allocated amount stays constant. The memory is
23          * volatile to prevent smart compilers from optimizing stuff out. */
24
25         std::unique_ptr <volatile char []> ptr (new volatile char [to_alloc]);
26         for (size_t i = 0; i < to_alloc; i += 4096) // FIXME: 4096 -> page size
27                 ptr[i] = 'a' + (i % ('z' - 'a'));
28
29         while (!global_stop)
30                 std::this_thread::sleep_for (std::chrono::seconds (1));
31
32         return nullptr;
33 }
34
35 static void get_total_ram ()
36 {
37         std::ifstream meminfo ("/proc/meminfo");
38
39         std::string entry_name;
40         meminfo >> entry_name >> total_ram_kb;
41
42         if (entry_name != "MemTotal:")
43                 throw std::runtime_error ("Unexpected format of /proc/meminfo");
44
45         std::cout << "Total RAM: " << total_ram_mb () << " MB" << std::endl;
46 }
47
48 unsigned long long operator "" _MB (unsigned long long n)
49 { return 1024 * 1024 * n; }
50
51 static void * mem_heavy_peak (void * arg)
52 { return do_mem (0.5f * total_ram_b ()); }
53
54 static void * mem_heavy_avg (void * arg)
55 { return do_mem (0.3f * total_ram_b ()); }
56
57 static void * mem_light (void * arg)
58 { return do_mem (25_MB); }
59
60 struct mem_handler : public dbus_signal_handler {
61         const std::string limitType;
62         static constexpr const char * const gtype = "(isdda{sv})";
63
64         mem_handler (const char * lt) : limitType (lt) { }
65
66         bool match (const gchar * objpath, const gchar * iface, GVariant * parameters) const override {
67                 if ("/Org/Tizen/StabilityMonitor/tsm_mem"s != objpath
68                 ||  "org.tizen.abnormality.mem.relative"s  != iface
69                 ||  !g_variant_is_of_type (parameters, G_VARIANT_TYPE(gtype)))
70                         return false;
71
72                 const char * paramType = nullptr;
73                 int pid = -1;
74                 g_variant_get (parameters, gtype, & pid, & paramType, nullptr, nullptr, nullptr);
75                 return pid == getpid() && limitType == paramType;
76         }
77 } handler_avg ("avg"), handler_peak ("peak");
78
79 bool run_mem_test (thread_func_t * func, size_t test_time, dbus_signal_handler * handler)
80 { return run_test (func, 1, handler, test_time); }
81
82 int main (int argc, char ** argv)
83 {
84         get_total_ram ();
85
86         const std::vector <std::pair <bool (*) (), std::string>> test_cases
87                 { { []() {
88                         /* Do a reasonable amount of memory (re)allocation.
89                          * Expect no signal. */
90                         return run_mem_test (mem_light, TEST_TIME_PEAK, & handler_peak);
91                 } , "small allocation (25 MB + overhead), expecting no signal"
92                 } , { []() {
93                         /* Allocate and keep lots of memory.
94                          * Expect a signal. */
95                         return ! run_mem_test (mem_heavy_peak, TEST_TIME_PEAK, & handler_peak);
96                 } , "heavy allocation (50% of total (" + std::to_string(size_t (0.5 * total_ram_mb ())) + " MB) + overhead), expecting peak signal"
97                 } , { []() {
98                         /* Allocate an amount of memory not high enough
99                          * to trigger peak, but keep it long enough to
100                          * trigger average. */
101                         return ! run_mem_test (mem_heavy_avg, TEST_TIME_AVG, & handler_avg);
102                 } , "medium allocation (30% of total (" + std::to_string(size_t (0.3 * total_ram_mb ())) + " MB) + overhead), expecting avg signal"
103                 }
104         };
105
106         return standard_main (test_cases, argc, argv);
107 }