xpcom/tests/TestExpirationTracker.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/xpcom/tests/TestExpirationTracker.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,204 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include <stdlib.h>
    1.11 +#include <stdio.h>
    1.12 +#include <prthread.h>
    1.13 +#include "nsExpirationTracker.h"
    1.14 +#include "nsMemory.h"
    1.15 +#include "nsAutoPtr.h"
    1.16 +#include "nsString.h"
    1.17 +#include "nsDirectoryServiceDefs.h"
    1.18 +#include "nsDirectoryServiceUtils.h"
    1.19 +#include "nsComponentManagerUtils.h"
    1.20 +#include "nsXPCOM.h"
    1.21 +#include "nsIFile.h"
    1.22 +#include "prinrval.h"
    1.23 +#include "nsThreadUtils.h"
    1.24 +
    1.25 +namespace TestExpirationTracker {
    1.26 +
    1.27 +struct Object {
    1.28 +  Object() : mExpired(false) { Touch(); }
    1.29 +  void Touch() { mLastUsed = PR_IntervalNow(); mExpired = false; }
    1.30 +
    1.31 +  nsExpirationState mExpiration;
    1.32 +  nsExpirationState* GetExpirationState() { return &mExpiration; }
    1.33 +
    1.34 +  PRIntervalTime mLastUsed;
    1.35 +  bool           mExpired;
    1.36 +};
    1.37 +
    1.38 +static bool error;
    1.39 +static uint32_t periodMS = 100;
    1.40 +static uint32_t ops = 1000;
    1.41 +static uint32_t iterations = 2;
    1.42 +static bool logging = 0;
    1.43 +static uint32_t sleepPeriodMS = 50;
    1.44 +static uint32_t slackMS = 20; // allow this much error
    1.45 +
    1.46 +static void SignalError() {
    1.47 +  printf("ERROR!\n");
    1.48 +  error = true;
    1.49 +}
    1.50 +
    1.51 +template <uint32_t K> class Tracker : public nsExpirationTracker<Object,K> {
    1.52 +public:
    1.53 +  Tracker() : nsExpirationTracker<Object,K>(periodMS) {
    1.54 +    Object* obj = new Object();
    1.55 +    mUniverse.AppendElement(obj);
    1.56 +    LogAction(obj, "Created");
    1.57 +  }
    1.58 +
    1.59 +  nsTArray<nsAutoArrayPtr<Object> > mUniverse;
    1.60 +
    1.61 +  void LogAction(Object* aObj, const char* aAction) {
    1.62 +    if (logging) {
    1.63 +      printf("%d %p(%d): %s\n", PR_IntervalNow(),
    1.64 +             static_cast<void*>(aObj), aObj->mLastUsed, aAction);
    1.65 +    }
    1.66 +  }
    1.67 +
    1.68 +  void DoRandomOperation() {
    1.69 +    Object* obj;
    1.70 +    switch (rand() & 0x7) {
    1.71 +    case 0: {
    1.72 +      if (mUniverse.Length() < 50) {
    1.73 +        obj = new Object();
    1.74 +        mUniverse.AppendElement(obj);
    1.75 +        nsExpirationTracker<Object,K>::AddObject(obj);
    1.76 +        LogAction(obj, "Created and added");
    1.77 +      }
    1.78 +      break;
    1.79 +    }
    1.80 +    case 4: {
    1.81 +      if (mUniverse.Length() < 50) {
    1.82 +        obj = new Object();
    1.83 +        mUniverse.AppendElement(obj);
    1.84 +        LogAction(obj, "Created");
    1.85 +      }
    1.86 +      break;
    1.87 +    }
    1.88 +    case 1: {
    1.89 +      obj = mUniverse[uint32_t(rand())%mUniverse.Length()];
    1.90 +      if (obj->mExpiration.IsTracked()) {
    1.91 +        nsExpirationTracker<Object,K>::RemoveObject(obj);
    1.92 +        LogAction(obj, "Removed");
    1.93 +      }
    1.94 +      break;
    1.95 +    }
    1.96 +    case 2: {
    1.97 +      obj = mUniverse[uint32_t(rand())%mUniverse.Length()];
    1.98 +      if (!obj->mExpiration.IsTracked()) {
    1.99 +        obj->Touch();
   1.100 +        nsExpirationTracker<Object,K>::AddObject(obj);
   1.101 +        LogAction(obj, "Added");
   1.102 +      }
   1.103 +      break;
   1.104 +    }
   1.105 +    case 3: {
   1.106 +      obj = mUniverse[uint32_t(rand())%mUniverse.Length()];
   1.107 +      if (obj->mExpiration.IsTracked()) {
   1.108 +        obj->Touch();
   1.109 +        nsExpirationTracker<Object,K>::MarkUsed(obj);
   1.110 +        LogAction(obj, "Marked used");
   1.111 +      }
   1.112 +      break;
   1.113 +    }
   1.114 +    }
   1.115 +  }
   1.116 +  
   1.117 +protected:
   1.118 +  void NotifyExpired(Object* aObj) {
   1.119 +    LogAction(aObj, "Expired");
   1.120 +    PRIntervalTime now = PR_IntervalNow();
   1.121 +    uint32_t timeDiffMS = (now - aObj->mLastUsed)*1000/PR_TicksPerSecond();
   1.122 +    // See the comment for NotifyExpired in nsExpirationTracker.h for these
   1.123 +    // bounds
   1.124 +    uint32_t lowerBoundMS = (K-1)*periodMS - slackMS;
   1.125 +    uint32_t upperBoundMS = K*(periodMS + sleepPeriodMS) + slackMS;
   1.126 +    if (logging) {
   1.127 +      printf("Checking: %d-%d = %d [%d,%d]\n",
   1.128 +             now, aObj->mLastUsed, timeDiffMS, lowerBoundMS, upperBoundMS);
   1.129 +    }
   1.130 +    if (timeDiffMS < lowerBoundMS || timeDiffMS > upperBoundMS) {
   1.131 +      if (timeDiffMS < periodMS && aObj->mExpired) {
   1.132 +        // This is probably OK, it probably just expired twice
   1.133 +      } else {
   1.134 +        SignalError();
   1.135 +      }
   1.136 +    }
   1.137 +    aObj->Touch();
   1.138 +    aObj->mExpired = true;
   1.139 +    DoRandomOperation();
   1.140 +    DoRandomOperation();
   1.141 +    DoRandomOperation();
   1.142 +  }
   1.143 +};
   1.144 +
   1.145 +template <uint32_t K> static bool test_random() {
   1.146 +  srand(K);
   1.147 +  error = false;
   1.148 + 
   1.149 +  for (uint32_t j = 0; j < iterations; ++j) {
   1.150 +    Tracker<K> tracker;
   1.151 +
   1.152 +    uint32_t i = 0;
   1.153 +    for (i = 0; i < ops; ++i) {
   1.154 +      if ((rand() & 0xF) == 0) {
   1.155 +        // Simulate work that takes time
   1.156 +        if (logging) {
   1.157 +          printf("SLEEPING for %dms (%d)\n", sleepPeriodMS, PR_IntervalNow());
   1.158 +        }
   1.159 +        PR_Sleep(PR_MillisecondsToInterval(sleepPeriodMS));
   1.160 +        // Process pending timer events
   1.161 +        NS_ProcessPendingEvents(nullptr);
   1.162 +      }
   1.163 +      tracker.DoRandomOperation();
   1.164 +    }
   1.165 +  }
   1.166 +  
   1.167 +  return !error;
   1.168 +}
   1.169 +
   1.170 +static bool test_random3() { return test_random<3>(); }
   1.171 +static bool test_random4() { return test_random<4>(); }
   1.172 +static bool test_random8() { return test_random<8>(); }
   1.173 +
   1.174 +typedef bool (*TestFunc)();
   1.175 +#define DECL_TEST(name) { #name, name }
   1.176 +
   1.177 +static const struct Test {
   1.178 +  const char* name;
   1.179 +  TestFunc    func;
   1.180 +} tests[] = {
   1.181 +  DECL_TEST(test_random3),
   1.182 +  DECL_TEST(test_random4),
   1.183 +  DECL_TEST(test_random8),
   1.184 +  { nullptr, nullptr }
   1.185 +};
   1.186 +
   1.187 +}
   1.188 +
   1.189 +using namespace TestExpirationTracker;
   1.190 +
   1.191 +int main(int argc, char **argv) {
   1.192 +  int count = 1;
   1.193 +  if (argc > 1)
   1.194 +    count = atoi(argv[1]);
   1.195 +
   1.196 +  if (NS_FAILED(NS_InitXPCOM2(nullptr, nullptr, nullptr)))
   1.197 +    return -1;
   1.198 +
   1.199 +  while (count--) {
   1.200 +    for (const Test* t = tests; t->name != nullptr; ++t) {
   1.201 +      printf("%25s : %s\n", t->name, t->func() ? "SUCCESS" : "FAILURE");
   1.202 +    }
   1.203 +  }
   1.204 +  
   1.205 +  NS_ShutdownXPCOM(nullptr);
   1.206 +  return 0;
   1.207 +}

mercurial