<commit_before>/**
 * @file EM.cpp
 * @brief mex interface for EM
 * @author Vladimir Eremeev
 * @date 2012
 */
#include "mexopencv.hpp"
#include "opencv2/ml/ml.hpp"
using namespace std;
using namespace cv;

// Persistent objects

/// Last object id to allocate
int last_id = 0;
/// Object container
map<int,EM> obj_;

/// CovMatType map for option processing
const ConstMap<string, int> CovMatType = ConstMap<string, int>
    ("Spherical", EM::COV_MAT_SPHERICAL)
    ("Diagonal",  EM::COV_MAT_DIAGONAL)
    ("Generic",   EM::COV_MAT_GENERIC);

/// CovMatTypeInv map for option processing
const ConstMap<int, string> CovMatTypeInv = ConstMap<int, string>
    (EM::COV_MAT_SPHERICAL, "Spherical")
    (EM::COV_MAT_DIAGONAL,  "Diagonal")
    (EM::COV_MAT_GENERIC,   "Generic");

// convenience macro to return results
#define assign_lhs(ll, label, prob)  do { \
    plhs[0] = MxArray(ll); \
if (nlhs > 1) \
    plhs[1] = MxArray(label); \
if (nlhs > 2) \
    plhs[2] = MxArray(prob); \
} while(0)

/**
 * Main entry called from Matlab
 * @param nlhs number of left-hand-side arguments
 * @param plhs pointers to mxArrays in the left-hand-side
 * @param nrhs number of right-hand-side arguments
 * @param prhs pointers to mxArrays in the right-hand-side
 */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    // Check the number of arguments
    if (nrhs < 2 || nlhs > 3)
        mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

    // Argument vector
    vector<MxArray> rhs(prhs,prhs+nrhs);

    // Determine argument format between constructor or (id,method,...)
    int id = 0;
    string method;
    if (nrhs > 1 && rhs[0].isNumeric() && rhs[1].isChar()) {
        id = rhs[0].toInt();
        method = rhs[1].toString();
    } else {
        mexErrMsgIdAndTxt("mexopencv:error","Invalid arguments");
    }

    // Big operation switch
    if (method == "new") {
        if (nrhs > 3  && (nrhs % 2)==0) {

            int nclusters = EM::DEFAULT_NCLUSTERS;
            int covMatType = EM::COV_MAT_DIAGONAL;
            int maxIter = EM::DEFAULT_MAX_ITERS;
            double eps = FLT_EPSILON;

            for(int i = 2; i < nrhs; i += 2) {
                string key(rhs[i].toString());
                if (key == "nclusters") {
                    nclusters = rhs[i + 1].toInt();
                } else if (key == "covMatType") {
                    covMatType = CovMatType[rhs[i + 1].toString()];
                } else if (key == "maxIters") {
                    maxIter = rhs[i + 1].toInt();
                } else if (key == "epsilon") {
                    eps = rhs[i + 1].toDouble();
                }
            }

            obj_[++last_id] = EM(nclusters, covMatType, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, maxIter, eps));
        } else if (nrhs == 2)
            obj_[++last_id] = EM();
        else
            mexErrMsgIdAndTxt("mexopencv:error","Invalid arguments");

        plhs[0] = MxArray(last_id);
        return;
    }

    EM& obj = obj_[id];
    if (method == "delete") {
        if (nrhs != 2 || nlhs != 0)
            mexErrMsgIdAndTxt("mexopencv:error","Output not assigned");
        obj_.erase(id);
    } else if (method == "train") {
        if (nrhs != 3)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

        Mat samples = rhs[2].toMat();

        Mat log_likelihoods;
        Mat labels;
        Mat probs;

        obj.train(samples, log_likelihoods, labels, probs);

        assign_lhs(log_likelihoods, labels, probs);

    } else if (method == "trainE") {
        if (nrhs < 4 || (nrhs % 2) != 0)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

        Mat samples = rhs[2].toMat();
        Mat means0  = rhs[3].toMat();

        // transpose matrix for convenience
        if (means0.cols == obj.get<int>("nclusters") && means0.rows == samples.cols)
            means0 = means0.t();

        Mat covs0;
        Mat weights0;
        for(int i = 4; i < nrhs; i += 2) {
            string key = rhs[i].toString();
            if (key == "covs0") {
                covs0 = rhs[i + 1].toMat();
            } else if (key == "weights0") {
                weights0 = rhs[i + 1].toMat();
            }
        }

        Mat log_likelihoods;
        Mat labels;
        Mat probs;

        obj.trainE(samples, means0, covs0, weights0, log_likelihoods, labels, probs);

        assign_lhs(log_likelihoods, labels, probs);

    } else if (method == "trainM") {
        if (nrhs < 4)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

        Mat samples = rhs[2].toMat();
        Mat probs0  = rhs[3].toMat();

        // transpose matrix for convenience
        if (probs0.rows == obj.get<int>("nclusters") && probs0.cols == samples.rows)
            probs0 = probs0.t();

        Mat log_likelihoods;
        Mat labels;
        Mat probs;

        obj.trainM(samples, probs0, log_likelihoods, labels, probs);

        assign_lhs(log_likelihoods, labels, probs);
    } else if (method == "nclusters") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toInt());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<int>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "covMatType") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, CovMatType[rhs[2].toString()]);
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(CovMatTypeInv[obj.get<int>(method)]);
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "maxIters") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toInt());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<int>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "epsilon") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toDouble());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<double>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "weights" || method == "means") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<Mat>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "covs") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<vector<Mat> >(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "save") {
        if (nrhs == 3 && nlhs == 0) {
            string filename = rhs[2].toString();
            FileStorage fs(filename, FileStorage::WRITE);
            if (fs.isOpened()) {
                obj.write(fs);
            } else {
                ostringstream emsg;
                emsg << "Could not open file " << filename << " for writing";
                mexErrMsgIdAndTxt("mexopencv:error",emsg.str().c_str());
            }
        } else {
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        }
    } else if (method == "load") {
        if (nrhs == 3 && nlhs == 0) {
            string filename = rhs[2].toString();
            const FileStorage fs(filename, FileStorage::READ);
            if (fs.isOpened()) {
                const FileNode& fn = fs["StatModel.EM"];
                obj.read(fn);
            } else {
                ostringstream emsg;
                emsg << "Could not open file " << filename << " for reading";
                mexErrMsgIdAndTxt("mexopencv:error",emsg.str().c_str());
            }
        } else {
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        }
    } else if (method == "predict") {
        if (nrhs != 3)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of input arguments");

        Mat sample = rhs[2].toMat();

        Mat probs;
        Vec2d result = obj.predict(sample, probs);

        assign_lhs(result[0], result[1], probs);

    } else if (method == "isTrained") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.isTrained());
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    }
}
<commit_msg>Added cv.EM; Improved cv.FeatureDetector; Thanks Vladimir\!<commit_after>/**
 * @file EM.cpp
 * @brief mex interface for EM
 * @author Vladimir Eremeev
 * @date 2012
 */
#include "mexopencv.hpp"
#include "opencv2/ml/ml.hpp"
using namespace std;
using namespace cv;

// Persistent objects

/// Last object id to allocate
int last_id = 0;
/// Object container
map<int,EM> obj_;

/// CovMatType map for option processing
const ConstMap<string, int> CovMatType = ConstMap<string, int>
    ("Spherical", EM::COV_MAT_SPHERICAL)
    ("Diagonal",  EM::COV_MAT_DIAGONAL)
    ("Generic",   EM::COV_MAT_GENERIC);

/// CovMatTypeInv map for option processing
const ConstMap<int, string> CovMatTypeInv = ConstMap<int, string>
    (EM::COV_MAT_SPHERICAL, "Spherical")
    (EM::COV_MAT_DIAGONAL,  "Diagonal")
    (EM::COV_MAT_GENERIC,   "Generic");

// convenience macro to return results
#define assign_lhs(ll, label, prob)  do { \
    plhs[0] = MxArray(ll); \
if (nlhs > 1) \
    plhs[1] = MxArray(label); \
if (nlhs > 2) \
    plhs[2] = MxArray(prob); \
} while(0)

/**
 * Main entry called from Matlab
 * @param nlhs number of left-hand-side arguments
 * @param plhs pointers to mxArrays in the left-hand-side
 * @param nrhs number of right-hand-side arguments
 * @param prhs pointers to mxArrays in the right-hand-side
 */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{
    // Check the number of arguments
    if (nrhs < 2 || nlhs > 3)
        mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

    // Argument vector
    vector<MxArray> rhs(prhs,prhs+nrhs);

    // Determine argument format between constructor or (id,method,...)
    int id = 0;
    string method;
    if (nrhs > 1 && rhs[0].isNumeric() && rhs[1].isChar()) {
        id = rhs[0].toInt();
        method = rhs[1].toString();
    } else {
        mexErrMsgIdAndTxt("mexopencv:error","Invalid arguments");
    }

    // Big operation switch
    if (method == "new") {
        if (nrhs > 3  && (nrhs % 2)==0) {

            int nclusters = EM::DEFAULT_NCLUSTERS;
            int covMatType = EM::COV_MAT_DIAGONAL;
            int maxIter = EM::DEFAULT_MAX_ITERS;
            double eps = FLT_EPSILON;

            for(int i = 2; i < nrhs; i += 2) {
                string key(rhs[i].toString());
                if (key == "Nclusters") {
                    nclusters = rhs[i + 1].toInt();
                } else if (key == "CovMatType") {
                    covMatType = CovMatType[rhs[i + 1].toString()];
                } else if (key == "MaxIters") {
                    maxIter = rhs[i + 1].toInt();
                } else if (key == "Epsilon") {
                    eps = rhs[i + 1].toDouble();
                }
            }

            obj_[++last_id] = EM(nclusters, covMatType, TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, maxIter, eps));
        } else if (nrhs == 2)
            obj_[++last_id] = EM();
        else
            mexErrMsgIdAndTxt("mexopencv:error","Invalid arguments");

        plhs[0] = MxArray(last_id);
        return;
    }

    EM& obj = obj_[id];
    if (method == "delete") {
        if (nrhs != 2 || nlhs != 0)
            mexErrMsgIdAndTxt("mexopencv:error","Output not assigned");
        obj_.erase(id);
    } else if (method == "train") {
        if (nrhs != 3)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        Mat samples = rhs[2].toMat();
        Mat log_likelihoods;
        Mat labels;
        Mat probs;
        obj.train(samples, log_likelihoods, labels, probs);
        assign_lhs(log_likelihoods, labels, probs);
    } else if (method == "trainE") {
        if (nrhs < 4 || (nrhs % 2) != 0)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        Mat samples = rhs[2].toMat();
        Mat means0  = rhs[3].toMat();
        // transpose matrix for convenience
        if (means0.cols == obj.get<int>("nclusters") && means0.rows == samples.cols)
            means0 = means0.t();
        Mat covs0;
        Mat weights0;
        for(int i = 4; i < nrhs; i += 2) {
            string key = rhs[i].toString();
            if (key == "Covs0") {
                covs0 = rhs[i + 1].toMat();
            } else if (key == "Weights0") {
                weights0 = rhs[i + 1].toMat();
            }
        }

        Mat log_likelihoods;
        Mat labels;
        Mat probs;
        obj.trainE(samples, means0, covs0, weights0, log_likelihoods, labels, probs);
        assign_lhs(log_likelihoods, labels, probs);
    } else if (method == "trainM") {
        if (nrhs < 4)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");

        Mat samples = rhs[2].toMat();
        Mat probs0  = rhs[3].toMat();
        // transpose matrix for convenience
        if (probs0.rows == obj.get<int>("nclusters") && probs0.cols == samples.rows)
            probs0 = probs0.t();
        Mat log_likelihoods;
        Mat labels;
        Mat probs;
        obj.trainM(samples, probs0, log_likelihoods, labels, probs);
        assign_lhs(log_likelihoods, labels, probs);
    } else if (method == "nclusters") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toInt());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<int>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "covMatType") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, CovMatType[rhs[2].toString()]);
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(CovMatTypeInv[obj.get<int>(method)]);
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "maxIters") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toInt());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<int>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "epsilon") {
        if (nrhs == 3 && nlhs == 0)
            obj.set(method, rhs[2].toDouble());
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<double>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "weights" || method == "means") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<Mat>(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "covs") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.get<vector<Mat> >(method));
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "isTrained") {
        if (nrhs == 3 && nlhs == 0)
            mexErrMsgIdAndTxt("mexopencv:error","Attempt to set read-only property");
        else if (nrhs == 2 && nlhs == 1)
            plhs[0] = MxArray(obj.isTrained());
        else
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
    } else if (method == "save") {
        if (nrhs == 3 && nlhs == 0) {
            string filename = rhs[2].toString();
            FileStorage fs(filename, FileStorage::WRITE);
            if (fs.isOpened()) {
                obj.write(fs);
            } else {
                ostringstream emsg;
                emsg << "Could not open file " << filename << " for writing";
                mexErrMsgIdAndTxt("mexopencv:error",emsg.str().c_str());
            }
        } else {
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        }
    } else if (method == "load") {
        if (nrhs == 3 && nlhs == 0) {
            string filename = rhs[2].toString();
            const FileStorage fs(filename, FileStorage::READ);
            if (fs.isOpened()) {
                const FileNode& fn = fs["StatModel.EM"];
                obj.read(fn);
            } else {
                ostringstream emsg;
                emsg << "Could not open file " << filename << " for reading";
                mexErrMsgIdAndTxt("mexopencv:error",emsg.str().c_str());
            }
        } else {
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of arguments");
        }
    } else if (method == "predict") {
        if (nrhs != 3)
            mexErrMsgIdAndTxt("mexopencv:error","Wrong number of input arguments");
        Mat sample = rhs[2].toMat();
        Mat probs;
        Vec2d result = obj.predict(sample, probs);
        assign_lhs(result[0], result[1], probs);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if defined(OS_WIN)
#include <process.h>
#include <windows.h>
#endif

#include "base/multiprocess_test.h"
#include "base/platform_thread.h"
#include "base/simple_thread.h"
#include "base/shared_memory.h"
#include "base/stats_table.h"
#include "base/stats_counters.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"

namespace base {

class StatsTableTest : public MultiProcessTest {
 public:
  void DeleteShmem(std::string name) {
    base::SharedMemory mem;
    mem.Delete(UTF8ToWide(name));
  }
};

// Open a StatsTable and verify that we can write to each of the
// locations in the table.
TEST_F(StatsTableTest, VerifySlots) {
  const std::string kTableName = "VerifySlotsStatTable";
  const int kMaxThreads = 1;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);

  // Register a single thread.
  std::string thread_name = "mainThread";
  int slot_id = table.RegisterThread(thread_name);
  EXPECT_NE(slot_id, 0);

  // Fill up the table with counters.
  std::string counter_base_name = "counter";
  for (int index = 0; index < kMaxCounter; index++) {
    std::string counter_name = counter_base_name;
    StringAppendF(&counter_name, "counter.ctr%d", index);
    int counter_id = table.FindCounter(counter_name);
    EXPECT_GT(counter_id, 0);
  }

  // Try to allocate an additional thread.  Verify it fails.
  slot_id = table.RegisterThread("too many threads");
  EXPECT_EQ(slot_id, 0);

  // Try to allocate an additional counter.  Verify it fails.
  int counter_id = table.FindCounter(counter_base_name);
  EXPECT_EQ(counter_id, 0);

  DeleteShmem(kTableName);
}

// CounterZero will continually be set to 0.
const std::string kCounterZero = "CounterZero";
// Counter1313 will continually be set to 1313.
const std::string kCounter1313 = "Counter1313";
// CounterIncrement will be incremented each time.
const std::string kCounterIncrement = "CounterIncrement";
// CounterDecrement will be decremented each time.
const std::string kCounterDecrement = "CounterDecrement";
// CounterMixed will be incremented by odd numbered threads and
// decremented by even threads.
const std::string kCounterMixed = "CounterMixed";
// The number of thread loops that we will do.
const int kThreadLoops = 1000;

class StatsTableThread : public base::SimpleThread {
 public:
  StatsTableThread(std::string name, int id)
      : base::SimpleThread(name), id_(id) { }
  virtual void Run();
 private:
  int id_;
};

void StatsTableThread::Run() {
  // Each thread will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the thread scheduling.

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    StatsCounter mixed_counter(kCounterMixed);  // create this one in the loop
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    if (id_ % 2)
      mixed_counter.Decrement();
    else
      mixed_counter.Increment();
    PlatformThread::Sleep(index % 10);   // short wait
  }
}

// Create a few threads and have them poke on their counters.
// Currently disabled. See bug report below:
// TODO(maruel): http://crbug.com/10611
TEST_F(StatsTableTest, MultipleThreads) {
#if 0
  // Create a stats table.
  const std::string kTableName = "MultipleThreadStatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of threads to go bang on the various counters.
  // After we join the threads, we'll make sure the counters
  // contain the values we expected.
  StatsTableThread* threads[kMaxThreads];

  // Spawn the threads.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index] = new StatsTableThread("MultipleThreadsTest", index);
    threads[index]->Start();
  }

  // Wait for the threads to finish.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index]->Join();
    delete threads[index];
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  StatsCounter mixed_counter(kCounterMixed);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxThreads,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterMixed;
  EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kTableName);
#endif
}

const std::string kMPTableName = "MultipleProcessStatTable";

MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
  // Each process will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the scheduling.

  StatsTable table(kMPTableName, 0, 0);
  StatsTable::set_current(&table);
  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    PlatformThread::Sleep(index % 10);   // short wait
  }
  return 0;
}

// Create a few processes and have them poke on their counters.
TEST_F(StatsTableTest, MultipleProcesses) {
  // Create a stats table.
  const int kMaxProcs = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kMPTableName);
  StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
  StatsTable::set_current(&table);
  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of processes to go bang on the various counters.
  // After we join the processes, we'll make sure the counters
  // contain the values we expected.
  ProcessHandle procs[kMaxProcs];

  // Spawn the processes.
  for (int16 index = 0; index < kMaxProcs; index++) {
    procs[index] = this->SpawnChild(L"StatsTableMultipleProcessMain");
    EXPECT_NE(base::kNullProcessHandle, procs[index]);
  }

  // Wait for the processes to finish.
  for (int index = 0; index < kMaxProcs; index++) {
    EXPECT_TRUE(WaitForSingleProcess(procs[index], 60 * 1000));
    base::CloseProcessHandle(procs[index]);
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxProcs,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kMPTableName);
}

class MockStatsCounter : public StatsCounter {
 public:
  explicit MockStatsCounter(const std::string& name)
      : StatsCounter(name) {}
  int* Pointer() { return GetPtr(); }
};

// Test some basic StatsCounter operations
TEST_F(StatsTableTest, StatsCounter) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounter foo("foo");

  // Test initial state.
  EXPECT_TRUE(foo.Enabled());
  ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
  EXPECT_EQ(0, *(foo.Pointer()));
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Increment.
  while (*(foo.Pointer()) < 123) foo.Increment();
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(0);
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(-1);
  EXPECT_EQ(122, table.GetCounterValue("c:foo"));

  // Test Set.
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
  foo.Set(100);
  EXPECT_EQ(100, table.GetCounterValue("c:foo"));
  foo.Set(-1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Decrement.
  foo.Subtract(1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(0);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(-1);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  DeleteShmem(kTableName);
}

class MockStatsCounterTimer : public StatsCounterTimer {
 public:
  explicit MockStatsCounterTimer(const std::string& name)
      : StatsCounterTimer(name) {}

  TimeTicks start_time() { return start_time_; }
  TimeTicks stop_time() { return stop_time_; }
};

// Test some basic StatsCounterTimer operations
TEST_F(StatsTableTest, StatsCounterTimer) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounterTimer bar("bar");

  // Test initial state.
  EXPECT_FALSE(bar.Running());
  EXPECT_TRUE(bar.start_time().is_null());
  EXPECT_TRUE(bar.stop_time().is_null());

  // Do some timing.
  bar.Start();
  PlatformThread::Sleep(500);
  bar.Stop();
  EXPECT_LE(500, table.GetCounterValue("t:bar"));

  // Verify that timing again is additive.
  bar.Start();
  PlatformThread::Sleep(500);
  bar.Stop();
  EXPECT_LE(1000, table.GetCounterValue("t:bar"));
}

// Test some basic StatsRate operations
TEST_F(StatsTableTest, StatsRate) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsRate baz("baz");

  // Test initial state.
  EXPECT_FALSE(baz.Running());
  EXPECT_EQ(0, table.GetCounterValue("c:baz"));
  EXPECT_EQ(0, table.GetCounterValue("t:baz"));

  // Do some timing.
  baz.Start();
  PlatformThread::Sleep(500);
  baz.Stop();
  EXPECT_EQ(1, table.GetCounterValue("c:baz"));
  EXPECT_LE(500, table.GetCounterValue("t:baz"));

  // Verify that timing again is additive.
  baz.Start();
  PlatformThread::Sleep(500);
  baz.Stop();
  EXPECT_EQ(2, table.GetCounterValue("c:baz"));
  EXPECT_LE(1000, table.GetCounterValue("t:baz"));
}

// Test some basic StatsScope operations
TEST_F(StatsTableTest, StatsScope) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsCounterTimer foo("foo");
  StatsRate bar("bar");

  // Test initial state.
  EXPECT_EQ(0, table.GetCounterValue("t:foo"));
  EXPECT_EQ(0, table.GetCounterValue("t:bar"));
  EXPECT_EQ(0, table.GetCounterValue("c:bar"));

  // Try a scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(500);
  }
  EXPECT_LE(500, table.GetCounterValue("t:foo"));
  EXPECT_LE(500, table.GetCounterValue("t:bar"));
  EXPECT_EQ(1, table.GetCounterValue("c:bar"));

  // Try a second scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(500);
  }
  EXPECT_LE(1000, table.GetCounterValue("t:foo"));
  EXPECT_LE(1000, table.GetCounterValue("t:bar"));
  EXPECT_EQ(2, table.GetCounterValue("c:bar"));

  DeleteShmem(kTableName);
}

}  // namespace base
<commit_msg>Mark StatsTableTest.MultipleThreads as flaky instead of using #if 0.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#if defined(OS_WIN)
#include <process.h>
#include <windows.h>
#endif

#include "base/multiprocess_test.h"
#include "base/platform_thread.h"
#include "base/simple_thread.h"
#include "base/shared_memory.h"
#include "base/stats_table.h"
#include "base/stats_counters.h"
#include "base/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"

namespace base {

class StatsTableTest : public MultiProcessTest {
 public:
  void DeleteShmem(std::string name) {
    base::SharedMemory mem;
    mem.Delete(UTF8ToWide(name));
  }
};

// Open a StatsTable and verify that we can write to each of the
// locations in the table.
TEST_F(StatsTableTest, VerifySlots) {
  const std::string kTableName = "VerifySlotsStatTable";
  const int kMaxThreads = 1;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);

  // Register a single thread.
  std::string thread_name = "mainThread";
  int slot_id = table.RegisterThread(thread_name);
  EXPECT_NE(slot_id, 0);

  // Fill up the table with counters.
  std::string counter_base_name = "counter";
  for (int index = 0; index < kMaxCounter; index++) {
    std::string counter_name = counter_base_name;
    StringAppendF(&counter_name, "counter.ctr%d", index);
    int counter_id = table.FindCounter(counter_name);
    EXPECT_GT(counter_id, 0);
  }

  // Try to allocate an additional thread.  Verify it fails.
  slot_id = table.RegisterThread("too many threads");
  EXPECT_EQ(slot_id, 0);

  // Try to allocate an additional counter.  Verify it fails.
  int counter_id = table.FindCounter(counter_base_name);
  EXPECT_EQ(counter_id, 0);

  DeleteShmem(kTableName);
}

// CounterZero will continually be set to 0.
const std::string kCounterZero = "CounterZero";
// Counter1313 will continually be set to 1313.
const std::string kCounter1313 = "Counter1313";
// CounterIncrement will be incremented each time.
const std::string kCounterIncrement = "CounterIncrement";
// CounterDecrement will be decremented each time.
const std::string kCounterDecrement = "CounterDecrement";
// CounterMixed will be incremented by odd numbered threads and
// decremented by even threads.
const std::string kCounterMixed = "CounterMixed";
// The number of thread loops that we will do.
const int kThreadLoops = 1000;

class StatsTableThread : public base::SimpleThread {
 public:
  StatsTableThread(std::string name, int id)
      : base::SimpleThread(name), id_(id) { }
  virtual void Run();
 private:
  int id_;
};

void StatsTableThread::Run() {
  // Each thread will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the thread scheduling.

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    StatsCounter mixed_counter(kCounterMixed);  // create this one in the loop
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    if (id_ % 2)
      mixed_counter.Decrement();
    else
      mixed_counter.Increment();
    PlatformThread::Sleep(index % 10);   // short wait
  }
}

// Create a few threads and have them poke on their counters.
// Currently disabled. See bug report below:
// Flaky, http://crbug.com/10611
TEST_F(StatsTableTest, FLAKY_MultipleThreads) {
  // Create a stats table.
  const std::string kTableName = "MultipleThreadStatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of threads to go bang on the various counters.
  // After we join the threads, we'll make sure the counters
  // contain the values we expected.
  StatsTableThread* threads[kMaxThreads];

  // Spawn the threads.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index] = new StatsTableThread("MultipleThreadsTest", index);
    threads[index]->Start();
  }

  // Wait for the threads to finish.
  for (int index = 0; index < kMaxThreads; index++) {
    threads[index]->Join();
    delete threads[index];
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  StatsCounter mixed_counter(kCounterMixed);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxThreads,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxThreads * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterMixed;
  EXPECT_EQ((kMaxThreads % 2) * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kTableName);
}

const std::string kMPTableName = "MultipleProcessStatTable";

MULTIPROCESS_TEST_MAIN(StatsTableMultipleProcessMain) {
  // Each process will open the shared memory and set counters
  // concurrently in a loop.  We'll use some pauses to
  // mixup the scheduling.

  StatsTable table(kMPTableName, 0, 0);
  StatsTable::set_current(&table);
  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);
  for (int index = 0; index < kThreadLoops; index++) {
    zero_counter.Set(0);
    lucky13_counter.Set(1313);
    increment_counter.Increment();
    decrement_counter.Decrement();
    PlatformThread::Sleep(index % 10);   // short wait
  }
  return 0;
}

// Create a few processes and have them poke on their counters.
TEST_F(StatsTableTest, MultipleProcesses) {
  // Create a stats table.
  const int kMaxProcs = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kMPTableName);
  StatsTable table(kMPTableName, kMaxProcs, kMaxCounter);
  StatsTable::set_current(&table);
  EXPECT_EQ(0, table.CountThreadsRegistered());

  // Spin up a set of processes to go bang on the various counters.
  // After we join the processes, we'll make sure the counters
  // contain the values we expected.
  ProcessHandle procs[kMaxProcs];

  // Spawn the processes.
  for (int16 index = 0; index < kMaxProcs; index++) {
    procs[index] = this->SpawnChild(L"StatsTableMultipleProcessMain");
    EXPECT_NE(base::kNullProcessHandle, procs[index]);
  }

  // Wait for the processes to finish.
  for (int index = 0; index < kMaxProcs; index++) {
    EXPECT_TRUE(WaitForSingleProcess(procs[index], 60 * 1000));
    base::CloseProcessHandle(procs[index]);
  }

  StatsCounter zero_counter(kCounterZero);
  StatsCounter lucky13_counter(kCounter1313);
  StatsCounter increment_counter(kCounterIncrement);
  StatsCounter decrement_counter(kCounterDecrement);

  // Verify the various counters are correct.
  std::string name;
  name = "c:" + kCounterZero;
  EXPECT_EQ(0, table.GetCounterValue(name));
  name = "c:" + kCounter1313;
  EXPECT_EQ(1313 * kMaxProcs,
      table.GetCounterValue(name));
  name = "c:" + kCounterIncrement;
  EXPECT_EQ(kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  name = "c:" + kCounterDecrement;
  EXPECT_EQ(-kMaxProcs * kThreadLoops,
      table.GetCounterValue(name));
  EXPECT_EQ(0, table.CountThreadsRegistered());

  DeleteShmem(kMPTableName);
}

class MockStatsCounter : public StatsCounter {
 public:
  explicit MockStatsCounter(const std::string& name)
      : StatsCounter(name) {}
  int* Pointer() { return GetPtr(); }
};

// Test some basic StatsCounter operations
TEST_F(StatsTableTest, StatsCounter) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounter foo("foo");

  // Test initial state.
  EXPECT_TRUE(foo.Enabled());
  ASSERT_NE(foo.Pointer(), static_cast<int*>(0));
  EXPECT_EQ(0, *(foo.Pointer()));
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Increment.
  while (*(foo.Pointer()) < 123) foo.Increment();
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(0);
  EXPECT_EQ(123, table.GetCounterValue("c:foo"));
  foo.Add(-1);
  EXPECT_EQ(122, table.GetCounterValue("c:foo"));

  // Test Set.
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));
  foo.Set(100);
  EXPECT_EQ(100, table.GetCounterValue("c:foo"));
  foo.Set(-1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Set(0);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  // Test Decrement.
  foo.Subtract(1);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(0);
  EXPECT_EQ(-1, table.GetCounterValue("c:foo"));
  foo.Subtract(-1);
  EXPECT_EQ(0, table.GetCounterValue("c:foo"));

  DeleteShmem(kTableName);
}

class MockStatsCounterTimer : public StatsCounterTimer {
 public:
  explicit MockStatsCounterTimer(const std::string& name)
      : StatsCounterTimer(name) {}

  TimeTicks start_time() { return start_time_; }
  TimeTicks stop_time() { return stop_time_; }
};

// Test some basic StatsCounterTimer operations
TEST_F(StatsTableTest, StatsCounterTimer) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  MockStatsCounterTimer bar("bar");

  // Test initial state.
  EXPECT_FALSE(bar.Running());
  EXPECT_TRUE(bar.start_time().is_null());
  EXPECT_TRUE(bar.stop_time().is_null());

  // Do some timing.
  bar.Start();
  PlatformThread::Sleep(500);
  bar.Stop();
  EXPECT_LE(500, table.GetCounterValue("t:bar"));

  // Verify that timing again is additive.
  bar.Start();
  PlatformThread::Sleep(500);
  bar.Stop();
  EXPECT_LE(1000, table.GetCounterValue("t:bar"));
}

// Test some basic StatsRate operations
TEST_F(StatsTableTest, StatsRate) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsRate baz("baz");

  // Test initial state.
  EXPECT_FALSE(baz.Running());
  EXPECT_EQ(0, table.GetCounterValue("c:baz"));
  EXPECT_EQ(0, table.GetCounterValue("t:baz"));

  // Do some timing.
  baz.Start();
  PlatformThread::Sleep(500);
  baz.Stop();
  EXPECT_EQ(1, table.GetCounterValue("c:baz"));
  EXPECT_LE(500, table.GetCounterValue("t:baz"));

  // Verify that timing again is additive.
  baz.Start();
  PlatformThread::Sleep(500);
  baz.Stop();
  EXPECT_EQ(2, table.GetCounterValue("c:baz"));
  EXPECT_LE(1000, table.GetCounterValue("t:baz"));
}

// Test some basic StatsScope operations
TEST_F(StatsTableTest, StatsScope) {
  // Create a stats table.
  const std::string kTableName = "StatTable";
  const int kMaxThreads = 20;
  const int kMaxCounter = 5;
  DeleteShmem(kTableName);
  StatsTable table(kTableName, kMaxThreads, kMaxCounter);
  StatsTable::set_current(&table);

  StatsCounterTimer foo("foo");
  StatsRate bar("bar");

  // Test initial state.
  EXPECT_EQ(0, table.GetCounterValue("t:foo"));
  EXPECT_EQ(0, table.GetCounterValue("t:bar"));
  EXPECT_EQ(0, table.GetCounterValue("c:bar"));

  // Try a scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(500);
  }
  EXPECT_LE(500, table.GetCounterValue("t:foo"));
  EXPECT_LE(500, table.GetCounterValue("t:bar"));
  EXPECT_EQ(1, table.GetCounterValue("c:bar"));

  // Try a second scope.
  {
    StatsScope<StatsCounterTimer> timer(foo);
    StatsScope<StatsRate> timer2(bar);
    PlatformThread::Sleep(500);
  }
  EXPECT_LE(1000, table.GetCounterValue("t:foo"));
  EXPECT_LE(1000, table.GetCounterValue("t:bar"));
  EXPECT_EQ(2, table.GetCounterValue("c:bar"));

  DeleteShmem(kTableName);
}

}  // namespace base
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ttbasic.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: hr $ $Date: 2005-09-29 15:57:56 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include "mybasic.hxx"
#include "ttbasic.hxx"

MyBasic* TTBasic::CreateMyBasic()
{
    return new MyBasic;
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.5.118); FILE MERGED 2006/09/01 17:16:59 kaib 1.5.118.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ttbasic.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 09:58:43 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include "mybasic.hxx"
#include "ttbasic.hxx"

MyBasic* TTBasic::CreateMyBasic()
{
    return new MyBasic;
}
<|endoftext|>


<commit_before>#include "OCR.h"
#include <fstream>
#include <stdexcept>
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ExecUtil.h"
#include "FileUtil.h"
#include "util.h"

const std::string TESSERACT("/usr/bin/tesseract");
const int TIMEOUT(20); // in seconds

int OCR(const std::string &input_document_path, const std::string &output_document_path,
        const std::string &language_codes)
{
    if (::access(TESSERACT.c_str(), X_OK) != 0)
        throw std::runtime_error("in OCR: can't execute \"" + TESSERACT + "\"!");

    if (not language_codes.empty() and language_codes.length() < 3)
        throw std::runtime_error("in OCR: incorrect language code \"" + language_codes + "\"!");

    std::vector<std::string> args{ TESSERACT, input_document_path, "stdout" };
    if (not language_codes.empty()) {
        args.emplace_back("-l");
        args.emplace_back(language_codes);
    }

    return ExecUtil::Exec(TESSERACT, args, "", output_document_path, "", TIMEOUT) == 0;
}

int OCR(const std::string &input_document_path, const std::string &language_codes, std::string * const output) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    const int retval = OCR(input_document_path, output_filename, language_codes);
    if (retval == 0) {
        if (not ReadFile(output_filename, output))
            return -1;
    }

    return retval;
}

int OCR(const std::string &input_document, std::string * const output, const std::string &language_codes) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string input_filename(auto_temp_file.getFilePath());
    std::ofstream ocr_input(input_filename);
    if (ocr_input.fail())
        return -1;
    ocr_input.write(input_document.data(), input_document.size());
    if (ocr_input.fail())
        return -1;

    return OCR(input_filename, output, language_codes);
}
<commit_msg>which tesseract<commit_after>#include "OCR.h"
#include <fstream>
#include <stdexcept>
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ExecUtil.h"
#include "FileUtil.h"
#include "util.h"

const std::string TESSERACT(ExecUtil::Which("tesseract"));
const int TIMEOUT(20); // in seconds

int OCR(const std::string &input_document_path, const std::string &output_document_path,
        const std::string &language_codes)
{
    if (::access(TESSERACT.c_str(), X_OK) != 0)
        throw std::runtime_error("in OCR: can't execute \"" + TESSERACT + "\"!");

    if (not language_codes.empty() and language_codes.length() < 3)
        throw std::runtime_error("in OCR: incorrect language code \"" + language_codes + "\"!");

    std::vector<std::string> args{ TESSERACT, input_document_path, "stdout" };
    if (not language_codes.empty()) {
        args.emplace_back("-l");
        args.emplace_back(language_codes);
    }

    return ExecUtil::Exec(TESSERACT, args, "", output_document_path, "", TIMEOUT) == 0;
}

int OCR(const std::string &input_document_path, const std::string &language_codes, std::string * const output) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string &output_filename(auto_temp_file.getFilePath());
    const int retval = OCR(input_document_path, output_filename, language_codes);
    if (retval == 0) {
        if (not ReadFile(output_filename, output))
            return -1;
    }

    return retval;
}

int OCR(const std::string &input_document, std::string * const output, const std::string &language_codes) {
    const FileUtil::AutoTempFile auto_temp_file;
    const std::string input_filename(auto_temp_file.getFilePath());
    std::ofstream ocr_input(input_filename);
    if (ocr_input.fail())
        return -1;
    ocr_input.write(input_document.data(), input_document.size());
    if (ocr_input.fail())
        return -1;

    return OCR(input_filename, output, language_codes);
}
<|endoftext|>


<commit_before>/// Useful conversion in visual studio
const char* toConstChar(std::string strg)
{
  return strg.c_str();
}
<commit_msg>Update stringopps.cpp<commit_after>/// Useful conversion in visual studio
const char* toConstChar(std::string strg)
{
  return strg.c_str();
}

// Tracex howto
void printTracex()
{
TRACEX_MESSAGE("NBSTR: %ls, stdString: %s",
         bstrSting,
         strg.c_str();
}
<|endoftext|>


<commit_before>#include "geiger/benchmark.h"

#include <gtest/gtest.h>

struct Basic : public ::testing::Test
{
    static void SetUpTestCase()
    {
        geiger::init();
    }

    Basic()
    {
        m_suite.on_test_complete([this](const std::string&, const geiger::test_report&) { ++m_on_test_complete_calls; });
        m_suite.on_complete([this](const geiger::suite_report&) { ++m_on_complete_calls; });
    }

protected:
    geiger::suite<> m_suite;
    int m_on_test_complete_calls = 0;
    int m_on_complete_calls = 0;
};

TEST_F(Basic, NoTest)
{
    m_suite.run();

    ASSERT_EQ(0, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, OneTest_Lambda)
{
    m_suite.add("foo", []() { });
    m_suite.run();

    ASSERT_EQ(1, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, TwoTests_Lambda)
{
    m_suite.add("foo", []() { });
    m_suite.add("bar", []() { });
    m_suite.run();

    ASSERT_EQ(2, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, TwoTests_RunTwice)
{
    m_suite.add("foo", []() { });
    m_suite.add("bar", []() { });
    m_suite.run();
    m_suite.run();

    ASSERT_EQ(4, m_on_test_complete_calls);
    ASSERT_EQ(2, m_on_complete_calls);
}
<commit_msg>Adding more basic unit tests<commit_after>#include "geiger/benchmark.h"

#include <gtest/gtest.h>

struct Basic : public ::testing::Test
{
    static void SetUpTestCase()
    {
        geiger::init();
    }

    Basic()
    {
        m_suite.on_test_complete([this](const std::string&, const geiger::test_report&) { ++m_on_test_complete_calls; });
        m_suite.on_complete([this](const geiger::suite_report&) { ++m_on_complete_calls; });
    }

protected:
    geiger::suite<> m_suite;
    int m_on_test_complete_calls = 0;
    int m_on_complete_calls = 0;
};

TEST_F(Basic, NoTest)
{
    m_suite.run();

    ASSERT_EQ(0, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, OneTest_Lambda)
{
    m_suite.add("foo", []() { });
    m_suite.run();

    ASSERT_EQ(1, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, TwoTests_Lambda)
{
    m_suite.add("foo", []() { });
    m_suite.add("bar", []() { });
    m_suite.run();

    ASSERT_EQ(2, m_on_test_complete_calls);
    ASSERT_EQ(1, m_on_complete_calls);
}

TEST_F(Basic, TwoTests_RunTwice)
{
    m_suite.add("foo", []() { });
    m_suite.add("bar", []() { });
    m_suite.run();
    m_suite.run();

    ASSERT_EQ(4, m_on_test_complete_calls);
    ASSERT_EQ(2, m_on_complete_calls);
}

TEST_F(Basic, OneTest_CorrectName)
{
    m_suite.add("foo", []() { });
    m_suite.on_test_complete([this](const std::string& name, const geiger::test_report&)
    {
        ASSERT_EQ("foo", name);

    });
    m_suite.run();
}

TEST_F(Basic, OneTest_NoPAPICounter)
{
    m_suite.add("foo", []() { });
    m_suite.on_test_complete([this](const std::string&, const geiger::test_report& report)
    {
        ASSERT_EQ(0, report.papi_counters().size());

    });
    m_suite.run();
}

TEST_F(Basic, TwoTests_CorrectOrderReports)
{
    m_suite.add("foo", []() { });
    m_suite.add("bar", []() { });
    m_suite.on_test_complete([this](const std::string& name, const geiger::test_report&)
    {
        static int i = 0;

        if (i++ == 0)
            ASSERT_EQ("foo", name);
        else
            ASSERT_EQ("bar", name);

    });
    m_suite.run();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
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 the author 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 "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/time.hpp"
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <iostream>

void test_swarm(bool super_seeding = false, bool strict = false, bool seed_mode = false, bool time_critical = false)
{
	using namespace libtorrent;

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_swarm", ec);
	remove_all("tmp2_swarm", ec);
	remove_all("tmp3_swarm", ec);

	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;
	session_proxy p3;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000), "0.0.0.0", 0);
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000), "0.0.0.0", 0);

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	settings.strict_super_seeding = strict;

	settings.upload_rate_limit = rate_limit;
	ses1.set_settings(settings);

	settings.download_rate_limit = rate_limit / 2;
	settings.upload_rate_limit = rate_limit;
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	add_torrent_params p;
	p.flags |= add_torrent_params::flag_seed_mode;
	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true
		, false, true, "_swarm", 8 * 1024, 0, super_seeding, &p);

	int mask = alert::all_categories & ~(alert::progress_notification | alert::performance_warning | alert::stats_notification);
	ses1.set_alert_mask(mask);
	ses2.set_alert_mask(mask);
	ses3.set_alert_mask(mask);

	if (time_critical)
	{
		tor2.set_piece_deadline(2, 0);
		tor2.set_piece_deadline(5, 1000);
		tor2.set_piece_deadline(8, 2000);
	}

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 80; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (st2.progress < 1.f && st2.progress > 0.5f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.5f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		print_ses_rate(i, &st1, &st2, &st3);

		if (st2.is_seeding && st3.is_seeding) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.status().is_seeding);
	TEST_CHECK(tor3.status().is_seeding);

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << average2 << std::endl;
	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	if (tor2.status().is_seeding && tor3.status().is_seeding) std::cerr << "done\n";

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	std::auto_ptr<alert> a = ses1.pop_alert();
	ptime end = time_now() + seconds(20);
	while (a.get() == 0 || dynamic_cast<torrent_deleted_alert*>(a.get()) == 0)
	{
		if (ses1.wait_for_alert(end - time_now()) == 0)
		{
			std::cerr << "wait_for_alert() expired" << std::endl;
			break;
		}
		a = ses1.pop_alert();
		assert(a.get());
		std::cerr << a->message() << std::endl;
	}

	TEST_CHECK(dynamic_cast<torrent_deleted_alert*>(a.get()) != 0);

	// there shouldn't be any alerts generated from now on
	// make sure that the timer in wait_for_alert() works
	// this should time out (ret == 0) and it should take
	// about 2 seconds
	ptime start = time_now_hires();
	alert const* ret;
	while ((ret = ses1.wait_for_alert(seconds(2))))
	{
		a = ses1.pop_alert();
		std::cerr << ret->message() << std::endl;
		start = time_now();
	}

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
	p3 = ses3.abort();

	TEST_CHECK(time_now_hires() - start < seconds(3));
	TEST_CHECK(time_now_hires() - start >= seconds(2));

	TEST_CHECK(!exists("tmp1_swarm/temporary"));
	TEST_CHECK(!exists("tmp2_swarm/temporary"));
	TEST_CHECK(!exists("tmp3_swarm/temporary"));

	remove_all("tmp1_swarm", ec);
	remove_all("tmp2_swarm", ec);
	remove_all("tmp3_swarm", ec);
}

int test_main()
{
	using namespace libtorrent;

	// with time critical pieces
	test_swarm(false, false, false, true);

	// with seed mode
	test_swarm(false, false, true);

	test_swarm();

	// with super seeding
	test_swarm(true);

	// with strict super seeding
	test_swarm(true, true);

	return 0;
}

<commit_msg>make super seeding test stricter<commit_after>/*

Copyright (c) 2008, Arvid Norberg
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 the author 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 "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/time.hpp"
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <iostream>

void test_swarm(bool super_seeding = false, bool strict = false, bool seed_mode = false, bool time_critical = false)
{
	using namespace libtorrent;

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_swarm", ec);
	remove_all("tmp2_swarm", ec);
	remove_all("tmp3_swarm", ec);

	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;
	session_proxy p3;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000), "0.0.0.0", 0);
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000), "0.0.0.0", 0);

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	settings.strict_super_seeding = strict;

	settings.upload_rate_limit = rate_limit;
	ses1.set_settings(settings);

	settings.download_rate_limit = rate_limit / 2;
	settings.upload_rate_limit = rate_limit;
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	add_torrent_params p;
	p.flags |= add_torrent_params::flag_seed_mode;
	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true
		, false, true, "_swarm", 8 * 1024, 0, super_seeding, &p);

	int mask = alert::all_categories & ~(alert::progress_notification | alert::performance_warning | alert::stats_notification);
	ses1.set_alert_mask(mask);
	ses2.set_alert_mask(mask);
	ses3.set_alert_mask(mask);

	if (time_critical)
	{
		tor2.set_piece_deadline(2, 0);
		tor2.set_piece_deadline(5, 1000);
		tor2.set_piece_deadline(8, 2000);
	}

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 80; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (super_seeding)
		{
			TEST_CHECK(st1.is_seeding);
			TEST_CHECK(st1.super_seeding);
		}

		if (st2.progress < 1.f && st2.progress > 0.5f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.5f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		print_ses_rate(i, &st1, &st2, &st3);

		if (st2.is_seeding && st3.is_seeding) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.status().is_seeding);
	TEST_CHECK(tor3.status().is_seeding);

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << average2 << std::endl;
	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	if (tor2.status().is_seeding && tor3.status().is_seeding) std::cerr << "done\n";

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	std::auto_ptr<alert> a = ses1.pop_alert();
	ptime end = time_now() + seconds(20);
	while (a.get() == 0 || dynamic_cast<torrent_deleted_alert*>(a.get()) == 0)
	{
		if (ses1.wait_for_alert(end - time_now()) == 0)
		{
			std::cerr << "wait_for_alert() expired" << std::endl;
			break;
		}
		a = ses1.pop_alert();
		assert(a.get());
		std::cerr << a->message() << std::endl;
	}

	TEST_CHECK(dynamic_cast<torrent_deleted_alert*>(a.get()) != 0);

	// there shouldn't be any alerts generated from now on
	// make sure that the timer in wait_for_alert() works
	// this should time out (ret == 0) and it should take
	// about 2 seconds
	ptime start = time_now_hires();
	alert const* ret;
	while ((ret = ses1.wait_for_alert(seconds(2))))
	{
		a = ses1.pop_alert();
		std::cerr << ret->message() << std::endl;
		start = time_now();
	}

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
	p3 = ses3.abort();

	TEST_CHECK(time_now_hires() - start < seconds(3));
	TEST_CHECK(time_now_hires() - start >= seconds(2));

	TEST_CHECK(!exists("tmp1_swarm/temporary"));
	TEST_CHECK(!exists("tmp2_swarm/temporary"));
	TEST_CHECK(!exists("tmp3_swarm/temporary"));

	remove_all("tmp1_swarm", ec);
	remove_all("tmp2_swarm", ec);
	remove_all("tmp3_swarm", ec);
}

int test_main()
{
	using namespace libtorrent;

	// with time critical pieces
	test_swarm(false, false, false, true);

	// with seed mode
	test_swarm(false, false, true);

	test_swarm();

	// with super seeding
	test_swarm(true);

	// with strict super seeding
	test_swarm(true, true);

	return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "media/base/buffers.h"
#include "media/base/filter_host.h"
#include "media/filters/video_thread.h"

namespace media {

// Limit our read ahead to three frames.  One frame is typically in flux at all
// times, as in frame n is discarded at the top of ThreadMain() while frame
// (n + kMaxFrames) is being asynchronously fetched.  The remaining two frames
// allow us to advance the current frame as well as read the timestamp of the
// following frame for more accurate timing.
//
// Increasing this number beyond 3 simply creates a larger buffer to work with
// at the expense of memory (~0.5MB and ~1.3MB per frame for 480p and 720p
// resolutions, respectively).  This can help on lower-end systems if there are
// difficult sections in the movie and decoding slows down.
static const size_t kMaxFrames = 3;

// Sleeping for negative amounts actually hangs your thread on Windows!
static const int64 kMinSleepMilliseconds = 0;

// This equates to ~13.33 fps, which is just under the typical 15 fps that lower
// quality cameras or shooting modes usually use for video encoding.
static const int64 kMaxSleepMilliseconds = 75;

VideoThread::VideoThread()
    : frame_available_(&lock_),
      state_(UNINITIALIZED),
      thread_(NULL),
      playback_rate_(0) {
}

VideoThread::~VideoThread() {
  AutoLock auto_lock(lock_);
  DCHECK(state_ == UNINITIALIZED || state_ == STOPPED);
}

// static
bool VideoThread::ParseMediaFormat(const media::MediaFormat& media_format,
                                   int* width_out, int* height_out) {
  std::string mime_type;
  if (!media_format.GetAsString(media::MediaFormat::kMimeType, &mime_type))
    return false;
  if (mime_type.compare(media::mime_type::kUncompressedVideo) != 0)
    return false;
  if (!media_format.GetAsInteger(media::MediaFormat::kWidth, width_out))
    return false;
  if (!media_format.GetAsInteger(media::MediaFormat::kHeight, height_out))
    return false;
  return true;
}

void VideoThread::Stop() {
  AutoLock auto_lock(lock_);
  state_ = STOPPED;
  if (thread_) {
    // Signal the thread since it's possible to get stopped with the video
    // thread waiting for a read to complete.
    frame_available_.Signal();
    {
      AutoUnlock auto_unlock(lock_);
      PlatformThread::Join(thread_);
    }
    thread_ = NULL;
  }
}

void VideoThread::SetPlaybackRate(float playback_rate) {
  AutoLock auto_lock(lock_);
  playback_rate_ = playback_rate;
}

void VideoThread::Seek(base::TimeDelta time) {
  // Do nothing.
}

bool VideoThread::Initialize(VideoDecoder* decoder) {
  AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, UNINITIALIZED);
  state_ = INITIALIZING;
  decoder_ = decoder;

  // Notify the pipeline of the video dimensions.
  int width = 0;
  int height = 0;
  if (!ParseMediaFormat(decoder->media_format(), &width, &height))
    return false;
  host_->SetVideoSize(width, height);

  // Initialize the subclass.
  // TODO(scherkus): do we trust subclasses not to do something silly while
  // we're holding the lock?
  if (!OnInitialize(decoder))
    return false;

  // Create our video thread.
  if (!PlatformThread::Create(0, this, &thread_)) {
    NOTREACHED() << "Video thread creation failed";
    return false;
  }

#if defined(OS_WIN)
  // Bump up our priority so our sleeping is more accurate.
  // TODO(scherkus): find out if this is necessary, but it seems to help.
  ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
#endif  // defined(OS_WIN)

  // Queue initial reads.
  for (size_t i = 0; i < kMaxFrames; ++i) {
    ScheduleRead();
  }

  return true;
}

// PlatformThread::Delegate implementation.
void VideoThread::ThreadMain() {
  PlatformThread::SetName("VideoThread");

  // Wait to be initialized so we can notify the first frame is available.
  if (!WaitForInitialized())
    return;
  OnFrameAvailable();

  for (;;) {
    // State and playback rate to assume for this iteration of the loop.
    State state;
    float playback_rate;
    {
      AutoLock auto_lock(lock_);
      state = state_;
      playback_rate = playback_rate_;
    }
    if (state == STOPPED) {
      return;
    }
    DCHECK_EQ(state, INITIALIZED);

    // Sleep for 10 milliseconds while paused.
    if (playback_rate == 0) {
      PlatformThread::Sleep(10);
      continue;
    }

    // Advance |current_frame_| and try to determine |next_frame|.
    scoped_refptr<VideoFrame> next_frame;
    {
      AutoLock auto_lock(lock_);
      DCHECK(!frames_.empty());
      DCHECK_EQ(current_frame_, frames_.front());
      frames_.pop_front();
      ScheduleRead();
      while (frames_.empty()) {
        frame_available_.Wait();

        // We have the lock again, check the actual state to see if we're trying
        // to stop.
        if (state_ == STOPPED) {
          return;
        }
      }
      current_frame_ = frames_.front();
      if (frames_.size() >= 2) {
        next_frame = frames_[1];
      }
    }

    // Notify subclass that |current_frame_| has been updated.
    OnFrameAvailable();

    // Determine the current and next presentation timestamps.
    base::TimeDelta now = host_->GetPipelineStatus()->GetTime();
    base::TimeDelta this_pts = current_frame_->GetTimestamp();
    base::TimeDelta next_pts;
    if (next_frame) {
      next_pts = next_frame->GetTimestamp();
    } else {
      next_pts = this_pts + current_frame_->GetDuration();
    }

    // Determine our sleep duration based on whether time advanced.
    base::TimeDelta sleep;
    if (now == previous_time_) {
      // Time has not changed, assume we sleep for the frame's duration.
      sleep = next_pts - this_pts;
    } else {
      // Time has changed, figure out real sleep duration.
      sleep = next_pts - now;
      previous_time_ = now;
    }

    // Scale our sleep based on the playback rate.
    // TODO(scherkus): floating point badness and degrade gracefully.
    int sleep_ms = static_cast<int>(sleep.InMicroseconds() / playback_rate /
        base::Time::kMicrosecondsPerMillisecond);

    // To be safe, limit our sleep duration.
    // TODO(scherkus): handle seeking gracefully.. right now a seek backwards
    // will hit kMinSleepMilliseconds whereas a seek forward will hit
    // kMaxSleepMilliseconds.
    if (sleep_ms < kMinSleepMilliseconds)
      sleep_ms = kMinSleepMilliseconds;
    else if (sleep_ms > kMaxSleepMilliseconds)
      sleep_ms = kMaxSleepMilliseconds;

    PlatformThread::Sleep(sleep_ms);
  }
}

void VideoThread::GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out) {
  AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, INITIALIZED);
  DCHECK(current_frame_);
  *frame_out = current_frame_;
}

void VideoThread::OnReadComplete(VideoFrame* frame) {
  AutoLock auto_lock(lock_);
  frames_.push_back(frame);
  DCHECK_LE(frames_.size(), kMaxFrames);

  // Check for our initialization condition.
  if (state_ == INITIALIZING && frames_.size() == kMaxFrames) {
    state_ = INITIALIZED;
    current_frame_ = frames_.front();
    host_->InitializationComplete();
  }

  frame_available_.Signal();
}

void VideoThread::ScheduleRead() {
  host_->PostTask(
      NewRunnableMethod(decoder_.get(), &VideoDecoder::Read,
      NewCallback(this, &VideoThread::OnReadComplete)));
}

bool VideoThread::WaitForInitialized() {
  // This loop essentially handles preroll.  We wait until we've been fully
  // initialized so we can call OnFrameAvailable() to provide subclasses with
  // the first frame.
  AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, INITIALIZING);
  while (state_ == INITIALIZING) {
    frame_available_.Wait();
    if (state_ == STOPPED) {
      return false;
    }
  }
  DCHECK_EQ(state_, INITIALIZED);
  DCHECK(current_frame_);
  return true;
}

}  // namespace media
<commit_msg>Fix an aggressive DCHECK in media::VideoThread<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.  Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.

#include "media/base/buffers.h"
#include "media/base/filter_host.h"
#include "media/filters/video_thread.h"

namespace media {

// Limit our read ahead to three frames.  One frame is typically in flux at all
// times, as in frame n is discarded at the top of ThreadMain() while frame
// (n + kMaxFrames) is being asynchronously fetched.  The remaining two frames
// allow us to advance the current frame as well as read the timestamp of the
// following frame for more accurate timing.
//
// Increasing this number beyond 3 simply creates a larger buffer to work with
// at the expense of memory (~0.5MB and ~1.3MB per frame for 480p and 720p
// resolutions, respectively).  This can help on lower-end systems if there are
// difficult sections in the movie and decoding slows down.
static const size_t kMaxFrames = 3;

// Sleeping for negative amounts actually hangs your thread on Windows!
static const int64 kMinSleepMilliseconds = 0;

// This equates to ~13.33 fps, which is just under the typical 15 fps that lower
// quality cameras or shooting modes usually use for video encoding.
static const int64 kMaxSleepMilliseconds = 75;

VideoThread::VideoThread()
    : frame_available_(&lock_),
      state_(UNINITIALIZED),
      thread_(NULL),
      playback_rate_(0) {
}

VideoThread::~VideoThread() {
  AutoLock auto_lock(lock_);
  DCHECK(state_ == UNINITIALIZED || state_ == STOPPED);
}

// static
bool VideoThread::ParseMediaFormat(const media::MediaFormat& media_format,
                                   int* width_out, int* height_out) {
  std::string mime_type;
  if (!media_format.GetAsString(media::MediaFormat::kMimeType, &mime_type))
    return false;
  if (mime_type.compare(media::mime_type::kUncompressedVideo) != 0)
    return false;
  if (!media_format.GetAsInteger(media::MediaFormat::kWidth, width_out))
    return false;
  if (!media_format.GetAsInteger(media::MediaFormat::kHeight, height_out))
    return false;
  return true;
}

void VideoThread::Stop() {
  AutoLock auto_lock(lock_);
  state_ = STOPPED;
  if (thread_) {
    // Signal the thread since it's possible to get stopped with the video
    // thread waiting for a read to complete.
    frame_available_.Signal();
    {
      AutoUnlock auto_unlock(lock_);
      PlatformThread::Join(thread_);
    }
    thread_ = NULL;
  }
}

void VideoThread::SetPlaybackRate(float playback_rate) {
  AutoLock auto_lock(lock_);
  playback_rate_ = playback_rate;
}

void VideoThread::Seek(base::TimeDelta time) {
  // Do nothing.
}

bool VideoThread::Initialize(VideoDecoder* decoder) {
  AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, UNINITIALIZED);
  state_ = INITIALIZING;
  decoder_ = decoder;

  // Notify the pipeline of the video dimensions.
  int width = 0;
  int height = 0;
  if (!ParseMediaFormat(decoder->media_format(), &width, &height))
    return false;
  host_->SetVideoSize(width, height);

  // Initialize the subclass.
  // TODO(scherkus): do we trust subclasses not to do something silly while
  // we're holding the lock?
  if (!OnInitialize(decoder))
    return false;

  // Create our video thread.
  if (!PlatformThread::Create(0, this, &thread_)) {
    NOTREACHED() << "Video thread creation failed";
    return false;
  }

#if defined(OS_WIN)
  // Bump up our priority so our sleeping is more accurate.
  // TODO(scherkus): find out if this is necessary, but it seems to help.
  ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
#endif  // defined(OS_WIN)

  // Queue initial reads.
  for (size_t i = 0; i < kMaxFrames; ++i) {
    ScheduleRead();
  }

  return true;
}

// PlatformThread::Delegate implementation.
void VideoThread::ThreadMain() {
  PlatformThread::SetName("VideoThread");

  // Wait to be initialized so we can notify the first frame is available.
  if (!WaitForInitialized())
    return;
  OnFrameAvailable();

  for (;;) {
    // State and playback rate to assume for this iteration of the loop.
    State state;
    float playback_rate;
    {
      AutoLock auto_lock(lock_);
      state = state_;
      playback_rate = playback_rate_;
    }
    if (state == STOPPED) {
      return;
    }
    DCHECK_EQ(state, INITIALIZED);

    // Sleep for 10 milliseconds while paused.
    if (playback_rate == 0) {
      PlatformThread::Sleep(10);
      continue;
    }

    // Advance |current_frame_| and try to determine |next_frame|.
    scoped_refptr<VideoFrame> next_frame;
    {
      AutoLock auto_lock(lock_);
      DCHECK(!frames_.empty());
      DCHECK_EQ(current_frame_, frames_.front());
      frames_.pop_front();
      ScheduleRead();
      while (frames_.empty()) {
        frame_available_.Wait();

        // We have the lock again, check the actual state to see if we're trying
        // to stop.
        if (state_ == STOPPED) {
          return;
        }
      }
      current_frame_ = frames_.front();
      if (frames_.size() >= 2) {
        next_frame = frames_[1];
      }
    }

    // Notify subclass that |current_frame_| has been updated.
    OnFrameAvailable();

    // Determine the current and next presentation timestamps.
    base::TimeDelta now = host_->GetPipelineStatus()->GetTime();
    base::TimeDelta this_pts = current_frame_->GetTimestamp();
    base::TimeDelta next_pts;
    if (next_frame) {
      next_pts = next_frame->GetTimestamp();
    } else {
      next_pts = this_pts + current_frame_->GetDuration();
    }

    // Determine our sleep duration based on whether time advanced.
    base::TimeDelta sleep;
    if (now == previous_time_) {
      // Time has not changed, assume we sleep for the frame's duration.
      sleep = next_pts - this_pts;
    } else {
      // Time has changed, figure out real sleep duration.
      sleep = next_pts - now;
      previous_time_ = now;
    }

    // Scale our sleep based on the playback rate.
    // TODO(scherkus): floating point badness and degrade gracefully.
    int sleep_ms = static_cast<int>(sleep.InMicroseconds() / playback_rate /
        base::Time::kMicrosecondsPerMillisecond);

    // To be safe, limit our sleep duration.
    // TODO(scherkus): handle seeking gracefully.. right now a seek backwards
    // will hit kMinSleepMilliseconds whereas a seek forward will hit
    // kMaxSleepMilliseconds.
    if (sleep_ms < kMinSleepMilliseconds)
      sleep_ms = kMinSleepMilliseconds;
    else if (sleep_ms > kMaxSleepMilliseconds)
      sleep_ms = kMaxSleepMilliseconds;

    PlatformThread::Sleep(sleep_ms);
  }
}

void VideoThread::GetCurrentFrame(scoped_refptr<media::VideoFrame>* frame_out) {
  AutoLock auto_lock(lock_);
  // Either we have initialized or we have the current frame.
  DCHECK(state_ != INITIALIZED || current_frame_);
  *frame_out = current_frame_;
}

void VideoThread::OnReadComplete(VideoFrame* frame) {
  AutoLock auto_lock(lock_);
  frames_.push_back(frame);
  DCHECK_LE(frames_.size(), kMaxFrames);

  // Check for our initialization condition.
  if (state_ == INITIALIZING && frames_.size() == kMaxFrames) {
    state_ = INITIALIZED;
    current_frame_ = frames_.front();
    host_->InitializationComplete();
  }

  frame_available_.Signal();
}

void VideoThread::ScheduleRead() {
  host_->PostTask(
      NewRunnableMethod(decoder_.get(), &VideoDecoder::Read,
      NewCallback(this, &VideoThread::OnReadComplete)));
}

bool VideoThread::WaitForInitialized() {
  // This loop essentially handles preroll.  We wait until we've been fully
  // initialized so we can call OnFrameAvailable() to provide subclasses with
  // the first frame.
  AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, INITIALIZING);
  while (state_ == INITIALIZING) {
    frame_available_.Wait();
    if (state_ == STOPPED) {
      return false;
    }
  }
  DCHECK_EQ(state_, INITIALIZED);
  DCHECK(current_frame_);
  return true;
}

}  // namespace media
<|endoftext|>


<commit_before>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_FNV_HPP
#define OUZEL_MATH_FNV_HPP

#include <cstdint>

namespace ouzel
{
    namespace fnv
    {
        inline namespace detail
        {
            template <typename T> constexpr T prime;
            template <typename T> constexpr T offsetBasis;

            template <> constexpr uint32_t prime<uint32_t> = 16777619u;
            template <> constexpr uint32_t offsetBasis<uint32_t> = 2166136261u;
            template <> constexpr uint64_t prime<uint64_t> = 1099511628211u;
            template <> constexpr uint64_t offsetBasis<uint64_t> = 14695981039346656037u;
        }

        // Fowler / Noll / Vo (FNV) hash
        template <typename Result, typename Value>
        constexpr Result hash(const Value value, size_t i = 0, Result result = offsetBasis<Result>) noexcept
        {
            return (i < sizeof(Value)) ? hash<Result>(value, i + 1, (result * prime<Result>) ^ ((value >> (i * 8)) & 0xFF)) : result;
        }
    } // namespace fnv
} // namespace ouzel

#endif // OUZEL_MATH_FNV_HPP
<commit_msg>Initialize prime and offsetBasis to 0<commit_after>// Copyright 2015-2019 Elviss Strazdins. All rights reserved.

#ifndef OUZEL_MATH_FNV_HPP
#define OUZEL_MATH_FNV_HPP

#include <cstdint>

namespace ouzel
{
    namespace fnv
    {
        inline namespace detail
        {
            template <typename T> constexpr T prime = T(0);
            template <typename T> constexpr T offsetBasis = T(0);

            template <> constexpr uint32_t prime<uint32_t> = 16777619u;
            template <> constexpr uint32_t offsetBasis<uint32_t> = 2166136261u;
            template <> constexpr uint64_t prime<uint64_t> = 1099511628211u;
            template <> constexpr uint64_t offsetBasis<uint64_t> = 14695981039346656037u;
        }

        // Fowler / Noll / Vo (FNV) hash
        template <typename Result, typename Value>
        constexpr Result hash(const Value value, size_t i = 0, Result result = offsetBasis<Result>) noexcept
        {
            return (i < sizeof(Value)) ? hash<Result>(value, i + 1, (result * prime<Result>) ^ ((value >> (i * 8)) & 0xFF)) : result;
        }
    } // namespace fnv
} // namespace ouzel

#endif // OUZEL_MATH_FNV_HPP
<|endoftext|>


<commit_before><commit_msg>Disable kernel pre-compilation for now.<commit_after><|endoftext|>