summaryrefslogtreecommitdiffstats
path: root/dom/media/mediacapabilities/BenchmarkStorageParent.cpp
blob: 64ae6ddd445688f4afa9463ae1511145e2f75572 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "BenchmarkStorageParent.h"
#include "KeyValueStorage.h"

namespace mozilla {

/* Moving average window size. */
const int32_t AVG_WINDOW = 20;
/* Calculate the moving average for the new value aValue for the current window
 * aWindow and the already existing average aAverage. When the method returns
 * aAverage will contain the new average and aWindow will contain the new
 * window.*/
void BenchmarkStorageParent::MovingAverage(int32_t& aAverage, int32_t& aWindow,
                                           const int32_t aValue) {
  if (aWindow < AVG_WINDOW) {
    aAverage = (aAverage * aWindow + aValue) / (aWindow + 1);
    aWindow++;
    return;
  }
  MOZ_ASSERT(aWindow == AVG_WINDOW);
  aAverage = (aAverage - aAverage / aWindow) + (aValue / aWindow);
}

/* In order to decrease the number of times the database is accessed when the
 * moving average is stored or retrieved we use the same value to store _both_
 * the window and the average. The range of the average is limited since it is
 * a percentage (0-100), and the range of the window is limited
 * (1-20). Thus the number that is stored in the database is in the form
 * (digits): WWAAA. For example, the value stored when an average(A) of 88
 * corresponds to a window(W) 7 is 7088. The average of 100 that corresponds to
 * a window of 20 is 20100. The following methods are helpers to extract or
 * construct the stored value according to the above. */

/* Stored value will be in the form WWAAA(19098). We need to extract the window
 * (19) and the average score (98). The aValue will
 * be parsed, the aWindow will contain the window (of the moving average) and
 * the return value will contain the average itself. */
int32_t BenchmarkStorageParent::ParseStoredValue(int32_t aValue,
                                                 int32_t& aWindow) {
  MOZ_ASSERT(aValue > 999);
  MOZ_ASSERT(aValue < 100000);

  int32_t score = aValue % 1000;
  aWindow = (aValue / 1000) % 100;
  return score;
}

int32_t BenchmarkStorageParent::PrepareStoredValue(int32_t aScore,
                                                   int32_t aWindow) {
  MOZ_ASSERT(aScore >= 0);
  MOZ_ASSERT(aScore <= 100);
  MOZ_ASSERT(aWindow > 0);
  MOZ_ASSERT(aWindow < 21);

  return aWindow * 1000 + aScore;
}

BenchmarkStorageParent::BenchmarkStorageParent()
    : mStorage(new KeyValueStorage) {}

IPCResult BenchmarkStorageParent::RecvPut(const nsCString& aDbName,
                                          const nsCString& aKey,
                                          const int32_t& aValue) {
  // In order to calculate and store the new moving average, we need to get the
  // stored value and window first, to calculate the new score and window, and
  // then to store the new aggregated value.
  mStorage->Get(aDbName, aKey)
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [storage = mStorage, aDbName, aKey, aValue](int32_t aResult) {
            int32_t window = 0;
            int32_t average = 0;
            if (aResult >= 0) {
              // The key found.
              average = ParseStoredValue(aResult, window);
            }
            MovingAverage(average, window, aValue);
            int32_t newValue = PrepareStoredValue(average, window);
            // Avoid storing if the values are the same. This is an optimization
            // to minimize the disk usage.
            if (aResult != newValue) {
              storage->Put(aDbName, aKey, newValue);
            }
          },
          [](nsresult rv) { /*do nothing*/ });

  return IPC_OK();
}

IPCResult BenchmarkStorageParent::RecvGet(const nsCString& aDbName,
                                          const nsCString& aKey,
                                          GetResolver&& aResolve) {
  mStorage->Get(aDbName, aKey)
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [aResolve](int32_t aResult) {
            int32_t window = 0;  // not used
            aResolve(aResult < 0 ? -1 : ParseStoredValue(aResult, window));
          },
          [aResolve](nsresult rv) { aResolve(-1); });

  return IPC_OK();
}

IPCResult BenchmarkStorageParent::RecvCheckVersion(const nsCString& aDbName,
                                                   int32_t aVersion) {
  mStorage->Get(aDbName, "Version"_ns)
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [storage = mStorage, aDbName, aVersion](int32_t aResult) {
            if (aVersion != aResult) {
              storage->Clear(aDbName)->Then(
                  GetCurrentSerialEventTarget(), __func__,
                  [storage, aDbName, aVersion](bool) {
                    storage->Put(aDbName, "Version"_ns, aVersion);
                  },
                  [](nsresult rv) { /*do nothing*/ });
            }
          },
          [](nsresult rv) { /*do nothing*/ });

  return IPC_OK();
}

};  // namespace mozilla