Skip to content
Snippets Groups Projects
Commit fdd7251b authored by toole1's avatar toole1
Browse files

monad update, woot woot

git-svn-id: https://subversion.cs.illinois.edu/svn/cs225@5126 6fbd10e7-183d-0410-a318-cb416676e4f2
parent 4f436ed8
No related branches found
No related tags found
No related merge requests found
monad identification file monad identification file
This file is used for monad directory identification This file is used for monad directory identification
Built by toole1 on linux4.ews.illinois.edu Built by toole1 on linux4.ews.illinois.edu
Build Date: Mon Oct 17 22:44:50 CDT 2011 Build Date: Mon Oct 24 23:45:56 CDT 2011
No preview for this file type
...@@ -19,6 +19,7 @@ const char * date = "15 July 2011"; ...@@ -19,6 +19,7 @@ const char * date = "15 July 2011";
} }
const char * unit_test::pass_string = "~~PASSED~~"; const char * unit_test::pass_string = "~~PASSED~~";
const size_t header_length = 64;
void printInfo() void printInfo()
{ {
...@@ -47,18 +48,16 @@ void set_error_message() ...@@ -47,18 +48,16 @@ void set_error_message()
void header(const string & title) void header(const string & title)
{ {
cout << title << "..." << endl cout << title << "..." << endl
<< "================================" << endl; << string(header_length, '=') << endl;
} }
void warning(const string & message) void warning(const string & message)
{ {
cerr << endl cerr << endl
<< "********************************" << string(header_length, '*') << endl
"********************************" << endl
<< "WARNING!" << endl << "WARNING!" << endl
<< message << endl << message << endl
<< "********************************" << string(header_length, '*') << endl << endl;
"********************************" << endl << endl;
} }
...@@ -113,7 +112,7 @@ void testname(const unit_test & curr_test, int32_t max_testname_len, int32_t max ...@@ -113,7 +112,7 @@ void testname(const unit_test & curr_test, int32_t max_testname_len, int32_t max
void detailed_info(const unit_test & curr_test) void detailed_info(const unit_test & curr_test)
{ {
std::cout << "--------------------------------" << endl std::cout << string(header_length, '-') << endl
<< curr_test.name; << curr_test.name;
if (curr_test.is_valgrind) std::cout << " (run under valgrind)"; if (curr_test.is_valgrind) std::cout << " (run under valgrind)";
std::cout << " [" << curr_test.points << " points]" << endl; std::cout << " [" << curr_test.points << " points]" << endl;
...@@ -133,7 +132,7 @@ void detailed_info(const unit_test & curr_test) ...@@ -133,7 +132,7 @@ void detailed_info(const unit_test & curr_test)
cout << curr_test.timeout << "ms timeout)" << endl; cout << curr_test.timeout << "ms timeout)" << endl;
std::cout << "Output:" << endl std::cout << "Output:" << endl
<< "--------------------------------" << endl; << string(header_length, '-') << endl;
// Tab the output over to distinguish it from the test case // Tab the output over to distinguish it from the test case
if (output != "") if (output != "")
......
...@@ -60,19 +60,28 @@ namespace proxy ...@@ -60,19 +60,28 @@ namespace proxy
vector<unit_test> * global_tests = NULL; vector<unit_test> * global_tests = NULL;
output_check_map * global_output_checks = NULL; output_check_map * global_output_checks = NULL;
double runtime_ratio[TIME_COUNT] = double time_constant(size_t smaller, size_t larger) { return 1.0; }
double time_logn (size_t smaller, size_t larger) { return log(larger) / log(smaller); }
double time_linear (size_t smaller, size_t larger) { return (double)larger / smaller; }
double time_nlogn (size_t smaller, size_t larger) { return (larger*log(larger)) / (smaller*log(smaller)); }
double time_nsquared(size_t smaller, size_t larger) { return ((double)larger*larger) / ((double)smaller*smaller); }
double time_cubed (size_t smaller, size_t larger) { return ((double)larger*larger*larger) / ((double)smaller*smaller*smaller); }
double time_infinity(size_t smaller, size_t larger) { return std::numeric_limits<double>::max(); }
runtime_ratio_func runtime_ratio[TIME_COUNT] =
{ {
1.0, time_constant,
4.0, time_logn,
5.20411998, // for 400/100 time_linear,
// 8.0, time_nlogn,
16.0, time_nsquared,
64, time_cubed,
std::numeric_limits<double>::max() time_infinity
}; };
const char * runtime_str[TIME_COUNT] = const char * runtime_str[TIME_COUNT] =
{ {
"O(1)", "O(1)",
"O(logn)",
"O(n)", "O(n)",
"O(nlogn)", "O(nlogn)",
// "O(nrootn)", // "O(nrootn)",
...@@ -401,7 +410,7 @@ void RunTests::output_detailed_tests_info(int32_t score) ...@@ -401,7 +410,7 @@ void RunTests::output_detailed_tests_info(int32_t score)
if (!tests[test_i].passed() || opts::verbose) if (!tests[test_i].passed() || opts::verbose)
output::detailed_info(tests[test_i]); output::detailed_info(tests[test_i]);
cout << endl << "--------------------------------" << endl; cout << endl << string(64, '-') << endl; // TODO (toole1): poor style, should be refactored to monad_shared::output
} }
......
...@@ -6,9 +6,10 @@ ...@@ -6,9 +6,10 @@
#ifndef MONAD_PROXY_H #ifndef MONAD_PROXY_H
#define MONAD_PROXY_H #define MONAD_PROXY_H
#include <cmath> #include <math.h>
#include <iostream> #include <iostream>
#include <functional>
#include <limits> #include <limits>
#include <map> #include <map>
#include <string> #include <string>
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
namespace proxy namespace proxy
{ {
using namespace std;
using namespace monad_shared; using namespace monad_shared;
class RunTests; class RunTests;
...@@ -242,6 +244,7 @@ inline std::string assert_equals_help(T expected, T actual, const char * expstr, ...@@ -242,6 +244,7 @@ inline std::string assert_equals_help(T expected, T actual, const char * expstr,
enum proxy_runtime_t enum proxy_runtime_t
{ {
CONSTANT_TIME = 0, CONSTANT_TIME = 0,
LOGN_TIME,
N_TIME, N_TIME,
NLOGN_TIME, NLOGN_TIME,
// NROOTN_TIME, // NROOTN_TIME,
...@@ -253,35 +256,51 @@ enum proxy_runtime_t ...@@ -253,35 +256,51 @@ enum proxy_runtime_t
namespace proxy namespace proxy
{ {
extern double runtime_ratio[TIME_COUNT]; typedef double (*runtime_ratio_func)(size_t, size_t);
extern runtime_ratio_func runtime_ratio[TIME_COUNT];
extern const char * runtime_str[TIME_COUNT]; extern const char * runtime_str[TIME_COUNT];
struct TimeIterationsData
{
double timePerCall;
size_t iterations;
uint64_t totalTime;
};
template <typename Generator, typename Timer> TimeIterationsData timeIterationsImpl(Generator gen, Timer timeFunctor, size_t input_size);
template <typename Generator, typename Timer> TimeIterationsData timeIterations (Generator gen, Timer timeFunctor, size_t input_size);
template <typename GenResult, typename GenArg, typename Timer> TimeIterationsData timeIterations (GenResult (*gen)(GenArg), Timer timeFunctor, size_t input_size);
template <typename Generator, typename Timer> template <typename Generator, typename Timer>
uint64_t timeIterationsImpl(Generator gen, Timer timeFunctor, size_t input_size); bool assert_time_impl(Generator gen, Timer functor, proxy_runtime_t expectedTime, size_t size1 = 100, size_t size2 = 400);
template <typename Generator, typename Timer>
uint64_t timeIterations(Generator gen, Timer timeFunctor, size_t input_size);
template <typename GenResult, typename GenArg, typename Timer>
uint64_t timeIterations(GenResult (*gen)(GenArg), Timer timeFunctor, size_t input_size);
} }
#define ASSERT_TIME(gen, functor, expectedTime) \ #define ASSERT_TIME3(gen, functor, expectedTime) \
do { \ do { \
uint64_t diff400 = proxy::timeIterations(gen, functor, 400); \ if (proxy::assert_time_impl(gen, functor, expectedTime)) \
uint64_t diff100 = proxy::timeIterations(gen, functor, 100); \ FAIL(string("Runtime was larger than ") + proxy::runtime_str[expectedTime]); \
std::cout << diff400 << std::endl; \
std::cout << diff100 << std::endl; \
double ratio = (double)(diff400)/(diff100); \
double diffFromExpected = abs(ratio - proxy::runtime_ratio[expectedTime]); \
double diffFromWrong = abs(ratio - proxy::runtime_ratio[expectedTime + 1]); \
std::cout << ratio << std::endl; \
if (diffFromWrong < diffFromExpected) \
FAIL(string("Runtime was larger than ") + proxy::runtime_str[expectedTime] + util::to_string(ratio)); \
} while(0) } while(0)
#define ASSERT_TIME5(gen, functor, expectedTime, size1, size2) \
do { \
if (proxy::assert_time_impl(gen, functor, expectedTime, size1, size2)) \
FAIL(string("Runtime was larger than ") + proxy::runtime_str[expectedTime]); \
} while(0)
// Crazy hack for overloading!
// Arg counting from:
// http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/
// Overloading tips:
// http://stackoverflow.com/questions/3046889/optional-parameters-with-c-macros
#define ASSERT_TIME_SIXTH_ARG(a, b, c, d, e, f, ...) f
#define ASSERT_TIME(...) \
ASSERT_TIME_SIXTH_ARG(__VA_ARGS__, ASSERT_TIME5, 0, ASSERT_TIME3, 0, 0) (__VA_ARGS__)
namespace proxy { namespace proxy {
template <typename Generator, typename Timer> template <typename Generator, typename Timer>
uint64_t timeIterations(Generator gen, Timer timeFunctor, size_t input_size) TimeIterationsData timeIterations(Generator gen, Timer timeFunctor, size_t input_size)
{ {
return timeIterationsImpl( return timeIterationsImpl(
bind1st(mem_fun(&Generator::operator()), &gen), bind1st(mem_fun(&Generator::operator()), &gen),
...@@ -290,27 +309,86 @@ uint64_t timeIterations(Generator gen, Timer timeFunctor, size_t input_size) ...@@ -290,27 +309,86 @@ uint64_t timeIterations(Generator gen, Timer timeFunctor, size_t input_size)
} }
template <typename GenResult, typename GenArg, typename Timer> template <typename GenResult, typename GenArg, typename Timer>
uint64_t timeIterations(GenResult (*gen)(GenArg), Timer timeFunctor, size_t input_size) TimeIterationsData timeIterations(GenResult (*gen)(GenArg), Timer timeFunctor, size_t input_size)
{ {
return timeIterationsImpl(ptr_fun(gen), timeFunctor, input_size); return timeIterationsImpl(ptr_fun(gen), timeFunctor, input_size);
} }
template <typename Generator, typename Timer> template <typename Generator, typename Timer>
uint64_t timeIterationsImpl(Generator gen, Timer timeFunctor, size_t input_size) TimeIterationsData timeIterationsImpl(Generator gen, Timer timeFunctor, size_t input_size)
{
const uint64_t min_time = 1000000; // in microseconds
std::vector<typename Generator::result_type *> inputs;
inputs.reserve(2000); // arbitrary, guess at how big it will be
// Using pointers here allows us to avoid copying if the compiler supports copy elision
// Since we're intentionally using large inputs, this could potentially have a significant effect on speed
// We're also going to do something else weird here. Instead of generating a fixed number of inputs, we're
// going to generate inputs for a fixed time.
size_t max_iterations = 0;
for (uint64_t genstart = util::process_clock(); util::process_clock() - genstart < min_time; max_iterations++)
inputs.push_back(new typename Generator::result_type(gen(input_size)));
typename Generator::result_type warmup_temp = gen(1);
timeFunctor(warmup_temp); // Warm up time functor (i.e. initialize statics)
size_t succeeded_iterations;
uint64_t starttime = util::process_clock();
for (succeeded_iterations = 0; succeeded_iterations < max_iterations && util::process_clock() - starttime < min_time;)
for (uint32_t i = 0; i < 10 && succeeded_iterations < max_iterations; i++, succeeded_iterations++)
timeFunctor(*inputs[succeeded_iterations]);
uint64_t endtime = util::process_clock();
for (size_t i = 0; i < max_iterations; i++)
delete inputs[i];
TimeIterationsData result;
result.timePerCall = static_cast<double>(endtime - starttime) / succeeded_iterations;
result.iterations = succeeded_iterations;
result.totalTime = endtime - starttime;
return result;
}
inline void timeIterationsOutput(size_t size, const TimeIterationsData & data)
{ {
const size_t num_iterations = 2000; std::cout << "Input size " << size << ": "
std::vector<typename Generator::result_type> inputs; << data.iterations << " iterations in " << data.totalTime/1000 << " ms "
inputs.reserve(num_iterations); << "for an average of " << data.timePerCall << " us per call" << endl;
for (size_t i = 0; i < num_iterations; i++)
inputs.push_back(gen(input_size));
uint32_t starttime = util::process_clock();
for (size_t i = 0; i < num_iterations; i++)
timeFunctor(inputs[i]);
uint32_t endtime = util::process_clock();
return endtime - starttime;
} }
template <typename Generator, typename Timer>
bool assert_time_impl(Generator gen, Timer functor, proxy_runtime_t expectedTime, size_t size1, size_t size2)
{
TimeIterationsData diff0 = timeIterations(gen, functor, 1);
TimeIterationsData diff1 = timeIterations(gen, functor, size1);
TimeIterationsData diff2 = timeIterations(gen, functor, size2);
timeIterationsOutput( 1, diff0);
timeIterationsOutput(size1, diff1);
timeIterationsOutput(size2, diff2);
double ratio = (diff2.timePerCall - diff0.timePerCall) / (diff1.timePerCall - diff0.timePerCall);
double expected_ratio = proxy::runtime_ratio[expectedTime](size1, size2);
double toohigh_ratio = proxy::runtime_ratio[expectedTime + 1](size1, size2);
double diffFromExpected = fabs(ratio - expected_ratio);
double diffFromWrong = fabs(ratio - toohigh_ratio);
std::cout << "Actual ratio: " << ratio << std::endl;
std::cout << "Expected ratio: " << expected_ratio << std::endl;
std::cout << "Wrong/high ratio: " << toohigh_ratio << std::endl;
std::cout << "Diff from expected: " << diffFromExpected << std::endl;
std::cout << "Diff from wrong: " << diffFromWrong << std::endl;
#if 0 // This does not seem to be important. A sample of two iterations seems to work.
const size_t min_iters = 100;
if (diff0.iterations < min_iters || diff1.iterations < min_iters || diff2.iterations < min_iters)
{
std::cout << "Too few iterations: Code was too slow to be able to judge runtime accurately" << std::endl;
return true;
}
#endif
return (diffFromWrong < diffFromExpected);
}
inline int32_t bitflags(unsigned long a, unsigned long b, unsigned long c, inline int32_t bitflags(unsigned long a, unsigned long b, unsigned long c,
unsigned long d, unsigned long e) unsigned long d, unsigned long e)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment