summaryrefslogtreecommitdiff
path: root/plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc')
-rw-r--r--plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc2770
1 files changed, 2770 insertions, 0 deletions
diff --git a/plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc b/plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc
new file mode 100644
index 0000000000..7ad66cac32
--- /dev/null
+++ b/plugins/Dbx_kyoto/src/kyotocabinet/kcutiltest.cc
@@ -0,0 +1,2770 @@
+/*************************************************************************************************
+ * The test cases of the utility functions
+ * Copyright (C) 2009-2012 FAL Labs
+ * This file is part of Kyoto Cabinet.
+ * This program is free software: you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software Foundation, either version
+ * 3 of the License, or any later version.
+ * This program 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 General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see <http://www.gnu.org/licenses/>.
+ *************************************************************************************************/
+
+
+#include "cmdcommon.h"
+
+
+// constants
+const size_t LOCKSLOTNUM = 128; // number of lock slots
+const size_t FILEIOUNIT = 50; // file I/O unit size
+
+
+// global variables
+const char* g_progname; // program name
+uint32_t g_randseed; // random seed
+int64_t g_memusage; // memory usage
+
+
+// function prototypes
+int main(int argc, char** argv);
+static void usage();
+static void errprint(int32_t line, const char* format, ...);
+static void fileerrprint(kc::File* file, int32_t line, const char* func);
+static void filemetaprint(kc::File* file);
+static int32_t runmutex(int argc, char** argv);
+static int32_t runcond(int argc, char** argv);
+static int32_t runpara(int argc, char** argv);
+static int32_t runfile(int argc, char** argv);
+static int32_t runlhmap(int argc, char** argv);
+static int32_t runthmap(int argc, char** argv);
+static int32_t runtalist(int argc, char** argv);
+static int32_t runmisc(int argc, char** argv);
+static int32_t procmutex(int64_t rnum, int32_t thnum, double iv);
+static int32_t proccond(int64_t rnum, int32_t thnum, double iv);
+static int32_t procpara(int64_t rnum, int32_t thnum, double iv);
+static int32_t procfile(const char* path, int64_t rnum, int32_t thnum, bool rnd, int64_t msiz);
+static int32_t proclhmap(int64_t rnum, bool rnd, int64_t bnum);
+static int32_t procthmap(int64_t rnum, bool rnd, int64_t bnum);
+static int32_t proctalist(int64_t rnum, bool rnd);
+static int32_t procmisc(int64_t rnum);
+
+
+// main routine
+int main(int argc, char** argv) {
+ g_progname = argv[0];
+ const char* ebuf = kc::getenv("KCRNDSEED");
+ g_randseed = ebuf ? (uint32_t)kc::atoi(ebuf) : (uint32_t)(kc::time() * 1000);
+ mysrand(g_randseed);
+ g_memusage = memusage();
+ kc::setstdiobin();
+ if (argc < 2) usage();
+ int32_t rv = 0;
+ if (!std::strcmp(argv[1], "mutex")) {
+ rv = runmutex(argc, argv);
+ } else if (!std::strcmp(argv[1], "cond")) {
+ rv = runcond(argc, argv);
+ } else if (!std::strcmp(argv[1], "para")) {
+ rv = runpara(argc, argv);
+ } else if (!std::strcmp(argv[1], "file")) {
+ rv = runfile(argc, argv);
+ } else if (!std::strcmp(argv[1], "lhmap")) {
+ rv = runlhmap(argc, argv);
+ } else if (!std::strcmp(argv[1], "thmap")) {
+ rv = runthmap(argc, argv);
+ } else if (!std::strcmp(argv[1], "talist")) {
+ rv = runtalist(argc, argv);
+ } else if (!std::strcmp(argv[1], "misc")) {
+ rv = runmisc(argc, argv);
+ } else {
+ usage();
+ }
+ if (rv != 0) {
+ oprintf("FAILED: KCRNDSEED=%u PID=%ld", g_randseed, (long)kc::getpid());
+ for (int32_t i = 0; i < argc; i++) {
+ oprintf(" %s", argv[i]);
+ }
+ oprintf("\n\n");
+ }
+ return rv;
+}
+
+
+// print the usage and exit
+static void usage() {
+ eprintf("%s: test cases of the utility functions of Kyoto Cabinet\n", g_progname);
+ eprintf("\n");
+ eprintf("usage:\n");
+ eprintf(" %s mutex [-th num] [-iv num] rnum\n", g_progname);
+ eprintf(" %s para [-th num] [-iv num] rnum\n", g_progname);
+ eprintf(" %s cond [-th num] [-iv num] rnum\n", g_progname);
+ eprintf(" %s file [-th num] [-rnd] [-msiz num] path rnum\n", g_progname);
+ eprintf(" %s lhmap [-rnd] [-bnum num] rnum\n", g_progname);
+ eprintf(" %s thmap [-rnd] [-bnum num] rnum\n", g_progname);
+ eprintf(" %s talist [-rnd] rnum\n", g_progname);
+ eprintf(" %s misc rnum\n", g_progname);
+ eprintf("\n");
+ std::exit(1);
+}
+
+
+// print formatted error information string and flush the buffer
+static void errprint(int32_t line, const char* format, ...) {
+ std::string msg;
+ kc::strprintf(&msg, "%s: %d: ", g_progname, line);
+ va_list ap;
+ va_start(ap, format);
+ kc::vstrprintf(&msg, format, ap);
+ va_end(ap);
+ kc::strprintf(&msg, "\n");
+ std::cout << msg;
+ std::cout.flush();
+}
+
+
+// print error message of file
+static void fileerrprint(kc::File* file, int32_t line, const char* func) {
+ oprintf("%s: %d: %s: %s: %s\n", g_progname, line, func, file->path().c_str(), file->error());
+}
+
+
+// print members of file
+static void filemetaprint(kc::File* file) {
+ oprintf("size: %lld\n", (long long)file->size());
+}
+
+
+// parse arguments of mutex command
+static int32_t runmutex(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ int32_t thnum = 1;
+ double iv = 0.0;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-th")) {
+ if (++i >= argc) usage();
+ thnum = kc::atoix(argv[i]);
+ } else if (!std::strcmp(argv[i], "-iv")) {
+ if (++i >= argc) usage();
+ iv = kc::atof(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1 || thnum < 1) usage();
+ if (thnum > THREADMAX) thnum = THREADMAX;
+ int32_t rv = procmutex(rnum, thnum, iv);
+ return rv;
+}
+
+
+// parse arguments of cond command
+static int32_t runcond(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ int32_t thnum = 1;
+ double iv = 0.0;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-th")) {
+ if (++i >= argc) usage();
+ thnum = kc::atoix(argv[i]);
+ } else if (!std::strcmp(argv[i], "-iv")) {
+ if (++i >= argc) usage();
+ iv = kc::atof(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1 || thnum < 1) usage();
+ if (thnum > THREADMAX) thnum = THREADMAX;
+ int32_t rv = proccond(rnum, thnum, iv);
+ return rv;
+}
+
+
+// parse arguments of para command
+static int32_t runpara(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ int32_t thnum = 1;
+ double iv = 0.0;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-th")) {
+ if (++i >= argc) usage();
+ thnum = kc::atoix(argv[i]);
+ } else if (!std::strcmp(argv[i], "-iv")) {
+ if (++i >= argc) usage();
+ iv = kc::atof(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1 || thnum < 1) usage();
+ if (thnum > THREADMAX) thnum = THREADMAX;
+ int32_t rv = procpara(rnum, thnum, iv);
+ return rv;
+}
+
+
+// parse arguments of file command
+static int32_t runfile(int argc, char** argv) {
+ bool argbrk = false;
+ const char* path = NULL;
+ const char* rstr = NULL;
+ int32_t thnum = 1;
+ bool rnd = false;
+ int64_t msiz = 0;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-th")) {
+ if (++i >= argc) usage();
+ thnum = kc::atoix(argv[i]);
+ } else if (!std::strcmp(argv[i], "-rnd")) {
+ rnd = true;
+ } else if (!std::strcmp(argv[i], "-msiz")) {
+ if (++i >= argc) usage();
+ msiz = kc::atoix(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!path) {
+ argbrk = true;
+ path = argv[i];
+ } else if (!rstr) {
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!path || !rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1 || thnum < 1 || msiz < 0) usage();
+ if (thnum > THREADMAX) thnum = THREADMAX;
+ int32_t rv = procfile(path, rnum, thnum, rnd, msiz);
+ return rv;
+}
+
+
+// parse arguments of lhmap command
+static int32_t runlhmap(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ bool rnd = false;
+ int64_t bnum = -1;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-rnd")) {
+ rnd = true;
+ } else if (!std::strcmp(argv[i], "-bnum")) {
+ if (++i >= argc) usage();
+ bnum = kc::atoix(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1) usage();
+ int32_t rv = proclhmap(rnum, rnd, bnum);
+ return rv;
+}
+
+
+// parse arguments of thmap command
+static int32_t runthmap(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ bool rnd = false;
+ int64_t bnum = -1;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-rnd")) {
+ rnd = true;
+ } else if (!std::strcmp(argv[i], "-bnum")) {
+ if (++i >= argc) usage();
+ bnum = kc::atoix(argv[i]);
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1) usage();
+ int32_t rv = procthmap(rnum, rnd, bnum);
+ return rv;
+}
+
+
+// parse arguments of talist command
+static int32_t runtalist(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ bool rnd = false;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else if (!std::strcmp(argv[i], "-rnd")) {
+ rnd = true;
+ } else {
+ usage();
+ }
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1) usage();
+ int32_t rv = proctalist(rnum, rnd);
+ return rv;
+}
+
+
+// parse arguments of misc command
+static int32_t runmisc(int argc, char** argv) {
+ bool argbrk = false;
+ const char* rstr = NULL;
+ for (int32_t i = 2; i < argc; i++) {
+ if (!argbrk && argv[i][0] == '-') {
+ if (!std::strcmp(argv[i], "--")) {
+ argbrk = true;
+ } else usage();
+ } else if (!rstr) {
+ argbrk = true;
+ rstr = argv[i];
+ } else {
+ usage();
+ }
+ }
+ if (!rstr) usage();
+ int64_t rnum = kc::atoix(rstr);
+ if (rnum < 1) usage();
+ int32_t rv = procmisc(rnum);
+ return rv;
+}
+
+
+// perform mutex command
+static int32_t procmutex(int64_t rnum, int32_t thnum, double iv) {
+ oprintf("<Mutex Test>\n seed=%u rnum=%lld thnum=%d iv=%.3f\n\n",
+ g_randseed, (long long)rnum, thnum, iv);
+ bool err = false;
+ kc::Mutex mutex;
+ oprintf("mutex:\n");
+ double stime = kc::time();
+ class ThreadMutex : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::Mutex* mutex, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ mutex_ = mutex;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ mutex_->lock();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ mutex_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::Mutex* mutex_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadMutex threadmutexs[THREADMAX];
+ if (thnum < 2) {
+ threadmutexs[0].setparams(0, &mutex, rnum, thnum, iv);
+ threadmutexs[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadmutexs[i].setparams(i, &mutex, rnum, thnum, iv);
+ threadmutexs[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadmutexs[i].join();
+ }
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SlottedMutex smutex(LOCKSLOTNUM);
+ oprintf("slotted mutex:\n");
+ stime = kc::time();
+ class ThreadSlottedMutex : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedMutex* smutex,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ smutex_ = smutex;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ smutex_->lock(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ smutex_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedMutex* smutex_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedMutex threadsmutexs[THREADMAX];
+ if (thnum < 2) {
+ threadsmutexs[0].setparams(0, &smutex, rnum, thnum, iv);
+ threadsmutexs[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsmutexs[i].setparams(i, &smutex, rnum, thnum, iv);
+ threadsmutexs[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsmutexs[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SpinLock spinlock;
+ oprintf("spin lock:\n");
+ stime = kc::time();
+ class ThreadSpinLock : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SpinLock* spinlock, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ spinlock_ = spinlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ spinlock_->lock();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SpinLock* spinlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSpinLock threadspins[THREADMAX];
+ if (thnum < 2) {
+ threadspins[0].setparams(0, &spinlock, rnum, thnum, iv);
+ threadspins[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspins[i].setparams(i, &spinlock, rnum, thnum, iv);
+ threadspins[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspins[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SlottedSpinLock sspinlock(LOCKSLOTNUM);
+ oprintf("slotted spin lock:\n");
+ stime = kc::time();
+ class ThreadSlottedSpinLock : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedSpinLock* sspinlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ sspinlock_ = sspinlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ sspinlock_->lock(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ sspinlock_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedSpinLock* sspinlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedSpinLock threadsspinlocks[THREADMAX];
+ if (thnum < 2) {
+ threadsspinlocks[0].setparams(0, &sspinlock, rnum, thnum, iv);
+ threadsspinlocks[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsspinlocks[i].setparams(i, &sspinlock, rnum, thnum, iv);
+ threadsspinlocks[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsspinlocks[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::RWLock rwlock;
+ oprintf("reader-writer lock writer:\n");
+ stime = kc::time();
+ class ThreadRWLockWriter : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::RWLock* rwlock, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ rwlock_ = rwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ rwlock_->lock_writer();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ rwlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::RWLock* rwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadRWLockWriter threadrwlockwriters[THREADMAX];
+ if (thnum < 2) {
+ threadrwlockwriters[0].setparams(0, &rwlock, rnum, thnum, iv);
+ threadrwlockwriters[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadrwlockwriters[i].setparams(i, &rwlock, rnum, thnum, iv);
+ threadrwlockwriters[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadrwlockwriters[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("reader-writer lock reader:\n");
+ stime = kc::time();
+ class ThreadRWLockReader : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::RWLock* rwlock, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ rwlock_ = rwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ rwlock_->lock_reader();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ rwlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::RWLock* rwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadRWLockReader threadrwlockreaders[THREADMAX];
+ if (thnum < 2) {
+ threadrwlockreaders[0].setparams(0, &rwlock, rnum, thnum, iv);
+ threadrwlockreaders[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadrwlockreaders[i].setparams(i, &rwlock, rnum, thnum, iv);
+ threadrwlockreaders[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadrwlockreaders[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SlottedRWLock srwlock(LOCKSLOTNUM);
+ oprintf("slotted reader-writer lock writer:\n");
+ stime = kc::time();
+ class ThreadSlottedRWLockWriter : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedRWLock* srwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ srwlock_ = srwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ srwlock_->lock_writer(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ srwlock_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedRWLock* srwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedRWLockWriter threadsrwlockwriters[THREADMAX];
+ if (thnum < 2) {
+ threadsrwlockwriters[0].setparams(0, &srwlock, rnum, thnum, iv);
+ threadsrwlockwriters[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsrwlockwriters[i].setparams(i, &srwlock, rnum, thnum, iv);
+ threadsrwlockwriters[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsrwlockwriters[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("slotted reader-writer lock reader:\n");
+ stime = kc::time();
+ class ThreadSlottedRWLockReader : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedRWLock* srwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ srwlock_ = srwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ srwlock_->lock_reader(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ srwlock_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedRWLock* srwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedRWLockReader threadsrwlockreaders[THREADMAX];
+ if (thnum < 2) {
+ threadsrwlockreaders[0].setparams(0, &srwlock, rnum, thnum, iv);
+ threadsrwlockreaders[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsrwlockreaders[i].setparams(i, &srwlock, rnum, thnum, iv);
+ threadsrwlockreaders[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadsrwlockreaders[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SpinRWLock spinrwlock;
+ oprintf("spin reader-writer lock writer:\n");
+ stime = kc::time();
+ class ThreadSpinRWLockWriter : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SpinRWLock* spinrwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ spinrwlock_ = spinrwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ spinrwlock_->lock_writer();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinrwlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SpinRWLock* spinrwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSpinRWLockWriter threadspinrwlockwriters[THREADMAX];
+ if (thnum < 2) {
+ threadspinrwlockwriters[0].setparams(0, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockwriters[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockwriters[i].setparams(i, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockwriters[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockwriters[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("spin reader-writer lock reader:\n");
+ stime = kc::time();
+ class ThreadSpinRWLockReader : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SpinRWLock* spinrwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ spinrwlock_ = spinrwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ spinrwlock_->lock_reader();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinrwlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SpinRWLock* spinrwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSpinRWLockReader threadspinrwlockreaders[THREADMAX];
+ if (thnum < 2) {
+ threadspinrwlockreaders[0].setparams(0, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockreaders[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockreaders[i].setparams(i, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockreaders[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockreaders[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("spin reader-writer lock wicked:\n");
+ stime = kc::time();
+ class ThreadSpinRWLockWicked : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SpinRWLock* spinrwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ spinrwlock_ = spinrwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ if (i % 4 == 0) {
+ spinrwlock_->lock_writer();
+ if (i % 16 == 0) {
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinrwlock_->demote();
+ }
+ } else {
+ spinrwlock_->lock_reader();
+ if (i % 7 == 0) {
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinrwlock_->promote();
+ }
+ }
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ spinrwlock_->unlock();
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SpinRWLock* spinrwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSpinRWLockWicked threadspinrwlockwickeds[THREADMAX];
+ if (thnum < 2) {
+ threadspinrwlockwickeds[0].setparams(0, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockwickeds[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockwickeds[i].setparams(i, &spinrwlock, rnum, thnum, iv);
+ threadspinrwlockwickeds[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadspinrwlockwickeds[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::SlottedSpinRWLock ssrwlock(LOCKSLOTNUM);
+ oprintf("slotted spin reader-writer lock writer:\n");
+ stime = kc::time();
+ class ThreadSlottedSpinRWLockWriter : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedSpinRWLock* ssrwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ ssrwlock_ = ssrwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ ssrwlock_->lock_writer(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ ssrwlock_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedSpinRWLock* ssrwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedSpinRWLockWriter threadssrwlockwriters[THREADMAX];
+ if (thnum < 2) {
+ threadssrwlockwriters[0].setparams(0, &ssrwlock, rnum, thnum, iv);
+ threadssrwlockwriters[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadssrwlockwriters[i].setparams(i, &ssrwlock, rnum, thnum, iv);
+ threadssrwlockwriters[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadssrwlockwriters[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("slotted spin reader-writer lock reader:\n");
+ stime = kc::time();
+ class ThreadSlottedSpinRWLockReader : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::SlottedSpinRWLock* ssrwlock,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ ssrwlock_ = ssrwlock;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ size_t idx = i % LOCKSLOTNUM;
+ ssrwlock_->lock_reader(idx);
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ ssrwlock_->unlock(idx);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::SlottedSpinRWLock* ssrwlock_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadSlottedSpinRWLockReader threadssrwlockreaders[THREADMAX];
+ if (thnum < 2) {
+ threadssrwlockreaders[0].setparams(0, &ssrwlock, rnum, thnum, iv);
+ threadssrwlockreaders[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadssrwlockreaders[i].setparams(i, &ssrwlock, rnum, thnum, iv);
+ threadssrwlockreaders[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadssrwlockreaders[i].join();
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("atomic increment:\n");
+ stime = kc::time();
+ kc::AtomicInt64 anum;
+ anum = rnum * thnum;
+ class ThreadAtomic : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::AtomicInt64* anum, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ anum_ = anum;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ anum_->add(1);
+ *anum_ += 1;
+ *anum_ -= 1;
+ while (true) {
+ int64_t num = anum_->get();
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ if (anum_->cas(num, num + 1)) break;
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::AtomicInt64* anum_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ };
+ ThreadAtomic threadatomic[THREADMAX];
+ if (thnum < 2) {
+ threadatomic[0].setparams(0, &anum, rnum, thnum, iv);
+ threadatomic[0].run();
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadatomic[i].setparams(i, &anum, rnum, thnum, iv);
+ threadatomic[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadatomic[i].join();
+ }
+ }
+ if (anum.get() != rnum * thnum * 3) {
+ errprint(__LINE__, "AtomicInt64::get: %lld", (long long)anum.get());
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform cond command
+static int32_t proccond(int64_t rnum, int32_t thnum, double iv) {
+ oprintf("<Mutex Test>\n seed=%u rnum=%lld thnum=%d iv=%.3f\n\n",
+ g_randseed, (long long)rnum, thnum, iv);
+ bool err = false;
+ kc::Mutex mutex;
+ kc::CondVar cond;
+ oprintf("conditon variable:\n");
+ double stime = kc::time();
+ class ThreadCondVar : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::Mutex* mutex, kc::CondVar* cond,
+ int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ mutex_ = mutex;
+ cond_ = cond;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ active_ = 1;
+ }
+ bool active() {
+ return active_ > 0;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ mutex_->lock();
+ if (i % 2 < 1) {
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ }
+ if (i % 7 == 0) {
+ cond_->wait(mutex_, 0.001);
+ } else {
+ cond_->wait(mutex_);
+ }
+ mutex_->unlock();
+ if (i % 2 > 0) {
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ active_ = 0;
+ }
+ private:
+ int32_t id_;
+ kc::Mutex* mutex_;
+ kc::CondVar* cond_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ kc::AtomicInt64 active_;
+ };
+ ThreadCondVar threadcondvars[THREADMAX];
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcondvars[i].setparams(i, &mutex, &cond, rnum, thnum, iv);
+ threadcondvars[i].start();
+ }
+ int64_t cnt = 0;
+ while (true) {
+ if (iv > 0) {
+ kc::Thread::sleep(iv);
+ } else if (iv < 0) {
+ kc::Thread::yield();
+ }
+ int32_t actnum = 0;
+ for (int32_t i = 0; i < thnum; i++) {
+ if (threadcondvars[i].active()) actnum++;
+ bool lock = (cnt + i) % 5 == 0;
+ if (lock) mutex.lock();
+ if (cnt % (thnum + 1) < 1) {
+ cond.broadcast();
+ } else {
+ cond.signal();
+ }
+ if (lock) mutex.unlock();
+ }
+ if (actnum < 1) break;
+ cnt++;
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcondvars[i].join();
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ kc::CondMap cmap;
+ oprintf("conditon map:\n");
+ stime = kc::time();
+ class ThreadCondMap : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::CondMap* cmap, int64_t rnum, int32_t thnum, double iv) {
+ id_ = id;
+ cmap_ = cmap;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ iv_ = iv;
+ active_ = 1;
+ }
+ bool active() {
+ return active_ > 0;
+ }
+ void run() {
+ for (int64_t i = 1; i <= rnum_; i++) {
+ if (iv_ > 0) {
+ sleep(iv_);
+ } else if (iv_ < 0) {
+ yield();
+ }
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08d", (int)(i % thnum_));
+ cmap_->wait(kbuf, ksiz, 0.001);
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ active_ = 0;
+ }
+ private:
+ int32_t id_;
+ kc::CondMap* cmap_;
+ int64_t rnum_;
+ int32_t thnum_;
+ double iv_;
+ kc::AtomicInt64 active_;
+ };
+ ThreadCondMap threadcondmaps[THREADMAX];
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcondmaps[i].setparams(i, &cmap, rnum, thnum, iv);
+ threadcondmaps[i].start();
+ }
+ cnt = 0;
+ while (true) {
+ if (iv > 0) {
+ kc::Thread::sleep(iv);
+ } else if (iv < 0) {
+ kc::Thread::yield();
+ }
+ int32_t actnum = 0;
+ for (int32_t i = 0; i < thnum; i++) {
+ if (threadcondmaps[i].active()) actnum++;
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08d", (int)i);
+ bool lock = (cnt + i) % 5 == 0;
+ if (lock) mutex.lock();
+ if (cnt % (thnum + 1) < 1) {
+ cmap.broadcast(kbuf, ksiz);
+ } else {
+ cmap.signal(kbuf, ksiz);
+ }
+ if (lock) mutex.unlock();
+ }
+ if (cnt % 1024 < 1) cmap.broadcast_all();
+ if (actnum < 1) break;
+ cnt++;
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcondmaps[i].join();
+ }
+ if (cmap.count() != 0) {
+ errprint(__LINE__, "CondMap::count");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform para command
+static int32_t procpara(int64_t rnum, int32_t thnum, double iv) {
+ oprintf("<Parallel Test>\n seed=%u rnum=%lld thnum=%d iv=%.3f\n\n",
+ g_randseed, (long long)rnum, thnum, iv);
+ bool err = false;
+ double stime = kc::time();
+ class TaskQueueImpl : public kc::TaskQueue {
+ public:
+ void setparams(int32_t thnum, double iv) {
+ thnum_ = thnum;
+ iv_ = iv;
+ cnt_ = 0;
+ }
+ void do_task(kc::TaskQueue::Task* task) {
+ cnt_ += 1;
+ if (iv_ > 0) {
+ kc::Thread::sleep(iv_ * thnum_);
+ } else if (iv_ < 0) {
+ kc::Thread::yield();
+ }
+ delete task;
+ }
+ int64_t done_count() {
+ return cnt_;
+ }
+ private:
+ int32_t thnum_;
+ double iv_;
+ kc::AtomicInt64 cnt_;
+ };
+ TaskQueueImpl queue;
+ queue.setparams(thnum, iv);
+ queue.start(thnum);
+ for (int64_t i = 1; i <= rnum; i++) {
+ kc::TaskQueue::Task* task = new kc::TaskQueue::Task;
+ queue.add_task(task);
+ if (iv > 0) {
+ kc::Thread::sleep(iv);
+ } else if (iv < 0) {
+ kc::Thread::yield();
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ oprintf("count: %lld\n", queue.count());
+ oprintf("done: %lld\n", queue.done_count());
+ queue.finish();
+ if (queue.count() != 0) {
+ errprint(__LINE__, "TaskQueue::count");
+ err = true;
+ }
+ if (queue.done_count() != rnum) {
+ errprint(__LINE__, "TaskQueueImpl::done_count");
+ err = true;
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ int64_t musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform file command
+static int32_t procfile(const char* path, int64_t rnum, int32_t thnum, bool rnd, int64_t msiz) {
+ oprintf("<File Test>\n seed=%u path=%s rnum=%lld thnum=%d rnd=%d msiz=%lld\n\n",
+ g_randseed, path, (long long)rnum, thnum, rnd, (long long)msiz);
+ bool err = false;
+ kc::File file;
+ oprintf("opening the file:\n");
+ double stime = kc::time();
+ if (!file.open(path, kc::File::OWRITER | kc::File::OCREATE | kc::File::OTRUNCATE, msiz)) {
+ fileerrprint(&file, __LINE__, "File::open");
+ err = true;
+ }
+ double etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("writing:\n");
+ class ThreadWrite : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum, bool rnd) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ if (rnd_ && myrand(2) == 0) {
+ char rbuf[RECBUFSIZ];
+ size_t rsiz = myrand(FILEIOUNIT);
+ if (rsiz > 0) std::memset(rbuf, '*', rsiz);
+ if (!file_->append(rbuf, rsiz)) {
+ fileerrprint(file_, __LINE__, "File::append");
+ err_ = true;
+ }
+ } else {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ size_t rsiz = std::sprintf(rbuf, "[%048lld]", (long long)num);
+ if (!file_->write(off, rbuf, rsiz)) {
+ fileerrprint(file_, __LINE__, "File::write");
+ err_ = true;
+ }
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ bool err_;
+ };
+ ThreadWrite threadwrites[THREADMAX];
+ if (thnum < 2) {
+ threadwrites[0].setparams(0, &file, rnum, thnum, rnd);
+ threadwrites[0].run();
+ if (threadwrites[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadwrites[i].setparams(i, &file, rnum, thnum, rnd);
+ threadwrites[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadwrites[i].join();
+ if (threadwrites[i].error()) err = true;
+ }
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("reading:\n");
+ stime = kc::time();
+ class ThreadRead : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum, bool rnd) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t size = file_->size();
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ if (!file_->read(off, rbuf, FILEIOUNIT) && off + (int64_t)FILEIOUNIT < size) {
+ fileerrprint(file_, __LINE__, "File::read");
+ err_ = true;
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ bool err_;
+ };
+ ThreadRead threadreads[THREADMAX];
+ if (thnum < 2) {
+ threadreads[0].setparams(0, &file, rnum, thnum, rnd);
+ threadreads[0].run();
+ if (threadreads[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadreads[i].setparams(i, &file, rnum, thnum, rnd);
+ threadreads[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadreads[i].join();
+ if (threadreads[i].error()) err = true;
+ }
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ if (rnd) {
+ int64_t off = rnum * thnum * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ std::memset(rbuf, '@', FILEIOUNIT);
+ if (!file.write(off, rbuf, FILEIOUNIT)) {
+ fileerrprint(&file, __LINE__, "File::write");
+ err = true;
+ }
+ }
+ oprintf("fast writing:\n");
+ stime = kc::time();
+ class ThreadWriteFast : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum, bool rnd) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ size_t rsiz = std::sprintf(rbuf, "[%048lld]", (long long)num);
+ if (!file_->write_fast(off, rbuf, rsiz)) {
+ fileerrprint(file_, __LINE__, "File::write_fast");
+ err_ = true;
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ bool err_;
+ };
+ ThreadWriteFast threadwritefasts[THREADMAX];
+ if (thnum < 2) {
+ threadwritefasts[0].setparams(0, &file, rnum, thnum, rnd);
+ threadwritefasts[0].run();
+ if (threadwritefasts[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadwritefasts[i].setparams(i, &file, rnum, thnum, rnd);
+ threadwritefasts[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadwritefasts[i].join();
+ if (threadwritefasts[i].error()) err = true;
+ }
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("fast reading:\n");
+ stime = kc::time();
+ class ThreadReadFast : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum, bool rnd) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ if (!file_->read_fast(off, rbuf, FILEIOUNIT)) {
+ fileerrprint(file_, __LINE__, "File::read_fast");
+ err_ = true;
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ bool err_;
+ };
+ ThreadReadFast threadreadfasts[THREADMAX];
+ if (thnum < 2) {
+ threadreadfasts[0].setparams(0, &file, rnum, thnum, rnd);
+ threadreadfasts[0].run();
+ if (threadreadfasts[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadreadfasts[i].setparams(i, &file, rnum, thnum, rnd);
+ threadreadfasts[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadreadfasts[i].join();
+ if (threadreadfasts[i].error()) err = true;
+ }
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("committing transaction:\n");
+ stime = kc::time();
+ int64_t qsiz = file.size() / 4;
+ if (!file.begin_transaction(rnd ? myrand(100) == 0 : false, qsiz)) {
+ fileerrprint(&file, __LINE__, "File::begin_transaction");
+ err = true;
+ }
+ if (!file.write_transaction(0, qsiz)) {
+ fileerrprint(&file, __LINE__, "File::write_transaction");
+ err = true;
+ }
+ int64_t fsiz = rnd ? myrand(rnum * thnum * FILEIOUNIT) : rnum * thnum / 2 * FILEIOUNIT + 5;
+ if (!file.truncate(fsiz)) {
+ fileerrprint(&file, __LINE__, "File::truncate");
+ err = true;
+ }
+ if (file.size() != fsiz) {
+ fileerrprint(&file, __LINE__, "File::truncate");
+ err = true;
+ }
+ class ThreadCommit : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum,
+ bool rnd, int64_t fsiz) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ fsiz_ = fsiz;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ size_t rsiz = std::sprintf(rbuf, "[%048lld]", (long long)num);
+ if (i % 2 == 0 || off > fsiz_ - (int64_t)FILEIOUNIT) {
+ if (!file_->write(off, rbuf, rsiz)) {
+ fileerrprint(file_, __LINE__, "File::write");
+ err_ = true;
+ }
+ } else {
+ if (!file_->write_fast(off, rbuf, rsiz)) {
+ fileerrprint(file_, __LINE__, "File::write_fast");
+ err_ = true;
+ }
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ int64_t fsiz_;
+ bool err_;
+ };
+ ThreadCommit threadcommits[THREADMAX];
+ if (thnum < 2) {
+ threadcommits[0].setparams(0, &file, rnum, thnum, rnd, fsiz);
+ threadcommits[0].run();
+ if (threadcommits[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcommits[i].setparams(i, &file, rnum, thnum, rnd, fsiz);
+ threadcommits[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadcommits[i].join();
+ if (threadcommits[i].error()) err = true;
+ }
+ }
+ if (!file.end_transaction(true)) {
+ fileerrprint(&file, __LINE__, "File::end_transaction");
+ err = true;
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("aborting transaction:\n");
+ stime = kc::time();
+ qsiz = file.size() / 4;
+ if (!file.begin_transaction(rnd ? myrand(100) == 0 : false, qsiz)) {
+ fileerrprint(&file, __LINE__, "File::begin_transaction");
+ err = true;
+ }
+ if (!file.write_transaction(0, qsiz)) {
+ fileerrprint(&file, __LINE__, "File::write_transaction");
+ err = true;
+ }
+ int64_t osiz = file.size();
+ kc::StringTreeMap chkmap;
+ int64_t chknum = rnum / 100 + 1;
+ for (int64_t i = 0; i < chknum; i++) {
+ char rbuf[RECBUFSIZ];
+ int64_t roff = myrand(osiz);
+ int32_t rsiz = myrand(RECBUFSIZ);
+ if (file.read(roff, rbuf, rsiz)) {
+ std::string key = kc::strprintf("%lld:%d", (long long)roff, rsiz);
+ chkmap[key] = std::string(rbuf, rsiz);
+ }
+ }
+ fsiz = rnd ? myrand(rnum * thnum * FILEIOUNIT) : rnum * thnum / 2 * FILEIOUNIT + 5;
+ if (!file.truncate(fsiz)) {
+ fileerrprint(&file, __LINE__, "File::truncate");
+ err = true;
+ }
+ if (file.size() != fsiz) {
+ fileerrprint(&file, __LINE__, "File::truncate");
+ err = true;
+ }
+ class ThreadAbort : public kc::Thread {
+ public:
+ void setparams(int32_t id, kc::File* file, int64_t rnum, int32_t thnum,
+ bool rnd, int64_t fsiz) {
+ id_ = id;
+ file_ = file;
+ rnum_ = rnum;
+ thnum_ = thnum;
+ rnd_ = rnd;
+ fsiz_ = fsiz;
+ err_ = false;
+ }
+ bool error() {
+ return err_;
+ }
+ void run() {
+ int64_t base = id_ * rnum_;
+ int64_t range = rnum_ * thnum_;
+ for (int64_t i = 1; !err_ && i <= rnum_; i++) {
+ int64_t num = rnd_ ? myrand(range) : base + i - 1;
+ int64_t off = num * FILEIOUNIT;
+ char rbuf[RECBUFSIZ];
+ std::memset(rbuf, num, FILEIOUNIT);
+ if (i % 2 == 0 || off > fsiz_ - (int64_t)FILEIOUNIT) {
+ if (!file_->write(off, rbuf, FILEIOUNIT)) {
+ fileerrprint(file_, __LINE__, "File::write");
+ err_ = true;
+ }
+ } else {
+ if (!file_->write_fast(off, rbuf, FILEIOUNIT)) {
+ fileerrprint(file_, __LINE__, "File::write_fast");
+ err_ = true;
+ }
+ }
+ if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
+ oputchar('.');
+ if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ }
+ private:
+ int32_t id_;
+ kc::File* file_;
+ int64_t rnum_;
+ int32_t thnum_;
+ bool rnd_;
+ int64_t fsiz_;
+ bool err_;
+ };
+ ThreadAbort threadaborts[THREADMAX];
+ if (thnum < 2) {
+ threadaborts[0].setparams(0, &file, rnum, thnum, rnd, fsiz);
+ threadaborts[0].run();
+ if (threadaborts[0].error()) err = true;
+ } else {
+ for (int32_t i = 0; i < thnum; i++) {
+ threadaborts[i].setparams(i, &file, rnum, thnum, rnd, fsiz);
+ threadaborts[i].start();
+ }
+ for (int32_t i = 0; i < thnum; i++) {
+ threadaborts[i].join();
+ if (threadaborts[i].error()) err = true;
+ }
+ }
+ if (!file.end_transaction(false)) {
+ fileerrprint(&file, __LINE__, "File::end_transaction");
+ err = true;
+ }
+ if (file.size() != osiz) {
+ fileerrprint(&file, __LINE__, "File::end_transaction");
+ err = true;
+ }
+ for (kc::StringTreeMap::iterator it = chkmap.begin(); it != chkmap.end(); ++it) {
+ const char* key = it->first.c_str();
+ int64_t roff = kc::atoi(key);
+ int32_t rsiz = kc::atoi(std::strchr(key, ':') + 1);
+ char rbuf[RECBUFSIZ];
+ if (file.read(roff, rbuf, rsiz)) {
+ if (it->second != std::string(rbuf, rsiz)) {
+ fileerrprint(&file, __LINE__, "File::end_transaction");
+ err = true;
+ }
+ } else {
+ fileerrprint(&file, __LINE__, "File::end_transaction");
+ err = true;
+ }
+ }
+ etime = kc::time();
+ filemetaprint(&file);
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("closing the file:\n");
+ stime = kc::time();
+ if (!file.close()) {
+ fileerrprint(&file, __LINE__, "File::close");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("testing file utility functions:\n");
+ stime = kc::time();
+ std::string ostr = "_";
+ for (int32_t i = 0; i < 100; i++) {
+ ostr.append(path);
+ }
+ ostr.append("_");
+ if (!kc::File::write_file(path, ostr.c_str(), ostr.size())) {
+ errprint(__LINE__, "File::write_file");
+ err = true;
+ }
+ int64_t isiz;
+ char* ibuf = kc::File::read_file(path, &isiz);
+ if (ibuf) {
+ if (ostr != ibuf) {
+ errprint(__LINE__, "File::read_file");
+ err = true;
+ }
+ delete[] ibuf;
+ } else {
+ errprint(__LINE__, "File::read_file");
+ err = true;
+ }
+ kc::File::Status sbuf;
+ if (!kc::File::status(path, &sbuf) || sbuf.isdir || sbuf.size < 1) {
+ errprint(__LINE__, "File::status");
+ err = true;
+ }
+ if (!kc::File::status(kc::File::CDIRSTR, &sbuf) || !sbuf.isdir) {
+ errprint(__LINE__, "File::status");
+ err = true;
+ }
+ const std::string& abspath = kc::File::absolute_path(path);
+ if (abspath.empty()) {
+ errprint(__LINE__, "File::absolute_path");
+ err = true;
+ }
+ const std::string& tmppath = kc::strprintf("%s%ctmp", path, kc::File::EXTCHR);
+ if (!kc::File::rename(path, tmppath) || !kc::File::rename(tmppath, path)) {
+ errprint(__LINE__, "File::rename");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("testing directory utility functions:\n");
+ stime = kc::time();
+ std::vector<std::string> files;
+ if (!kc::File::read_directory(kc::File::CDIRSTR, &files)) {
+ errprint(__LINE__, "File::read_directory");
+ err = true;
+ }
+ if (!kc::File::make_directory(tmppath)) {
+ errprint(__LINE__, "File::make_directory");
+ err = true;
+ }
+ if (!kc::File::remove_directory(tmppath)) {
+ errprint(__LINE__, "File::remove_directory");
+ err = true;
+ }
+ if (!kc::File::make_directory(tmppath)) {
+ errprint(__LINE__, "File::make_directory");
+ err = true;
+ }
+ const std::string chldpath = tmppath + kc::File::PATHCHR + "tmp";
+ if (!kc::File::write_file(chldpath, tmppath.c_str(), tmppath.size())) {
+ errprint(__LINE__, "File::write_file");
+ err = true;
+ }
+ if (!kc::File::remove_recursively(tmppath)) {
+ errprint(__LINE__, "File::make_recursively");
+ err = true;
+ }
+ const std::string& cwdpath = kc::File::get_current_directory();
+ if (cwdpath.empty()) {
+ errprint(__LINE__, "File::get_current_directory");
+ err = true;
+ }
+ if (!kc::File::set_current_directory(cwdpath)) {
+ errprint(__LINE__, "File::set_current_directory");
+ err = true;
+ }
+ kc::DirStream dir;
+ if (!dir.open(cwdpath)) {
+ errprint(__LINE__, "DirStream::open");
+ err = true;
+ }
+ std::string cpath;
+ while (dir.read(&cpath)) {
+ if (!kc::File::status(cpath, &sbuf)) {
+ errprint(__LINE__, "File::status");
+ err = true;
+ }
+ }
+ if (!dir.close()) {
+ errprint(__LINE__, "DirStream::close");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform lhmap command
+static int32_t proclhmap(int64_t rnum, bool rnd, int64_t bnum) {
+ oprintf("<Doubly-linked Hash Map Test>\n seed=%u rnum=%lld rnd=%d bnum=%lld\n\n",
+ g_randseed, (long long)rnum, rnd, (long long)bnum);
+ bool err = false;
+ if (bnum < 0) bnum = 0;
+ typedef kc::LinkedHashMap<std::string, std::string> Map;
+ Map map(bnum);
+ oprintf("setting records:\n");
+ double stime = kc::time();
+ for (int64_t i = 1; i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ map.set(kbuf, kbuf, Map::MCURRENT);
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ int64_t musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("getting records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ Map::MoveMode mode = Map::MCURRENT;
+ if (rnd) {
+ switch (myrand(4)) {
+ case 0: mode = Map::MFIRST;
+ case 1: mode = Map::MLAST;
+ }
+ }
+ if (!map.get(kbuf, mode) && !rnd) {
+ errprint(__LINE__, "LinkedHashMap::get: %s", kbuf);
+ err = true;
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("traversing records:\n");
+ stime = kc::time();
+ int64_t cnt = 0;
+ for (Map::Iterator it = map.begin(); !err && it != map.end(); ++it) {
+ cnt++;
+ if (it.key() != it.value()) {
+ errprint(__LINE__, "LinkedHashMap::Iterator::key");
+ err = true;
+ }
+ if (rnum > 250 && cnt % (rnum / 250) == 0) {
+ oputchar('.');
+ if (cnt == rnum || cnt % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt);
+ }
+ }
+ if (rnd) oprintf(" (end)\n");
+ if (cnt != (int64_t)map.count()) {
+ errprint(__LINE__, "LinkedHashMap::count");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ Map paramap(bnum + 31);
+ oprintf("migrating records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ Map::MoveMode mode = Map::MCURRENT;
+ if (rnd) {
+ switch (myrand(4)) {
+ case 0: mode = Map::MFIRST;
+ case 1: mode = Map::MLAST;
+ }
+ }
+ if (!map.migrate(kbuf, &paramap, mode) && !rnd) {
+ errprint(__LINE__, "LinkedHashMap::migrate: %s", kbuf);
+ err = true;
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld,%lld\n", (long long)map.count(), (long long)paramap.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("removing records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ if (!paramap.remove(kbuf) && !rnd) {
+ errprint(__LINE__, "LinkedHashMap::remove: %s", kbuf);
+ err = true;
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld,%lld\n", (long long)map.count(), (long long)paramap.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ if (rnd) {
+ oprintf("wicked testing:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ Map::MoveMode mode = Map::MCURRENT;
+ if (rnd) {
+ switch (myrand(4)) {
+ case 0: mode = Map::MFIRST;
+ case 1: mode = Map::MLAST;
+ }
+ }
+ Map *ptr = &map;
+ Map *paraptr = &paramap;
+ if (myrand(2) == 0) {
+ ptr = &paramap;
+ paraptr = &map;
+ }
+ switch (myrand(4)) {
+ case 0: {
+ ptr->set(kbuf, kbuf, mode);
+ break;
+ }
+ case 1: {
+ ptr->get(kbuf, mode);
+ break;
+ }
+ case 2: {
+ ptr->remove(kbuf);
+ break;
+ }
+ case 3: {
+ ptr->migrate(kbuf, paraptr, mode);
+ break;
+ }
+ }
+ if (myrand(rnum * 2 + 1) == 0) ptr->clear();
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ cnt = 0;
+ for (Map::Iterator it = map.begin(); !err && it != map.end(); ++it) {
+ cnt++;
+ if (it.key() != it.value()) {
+ errprint(__LINE__, "LinkedHashMap::Iterator::key");
+ err = true;
+ }
+ if (rnum > 250 && cnt % (rnum / 250) == 0) {
+ oputchar('.');
+ if (cnt == rnum || cnt % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt);
+ }
+ }
+ if (rnd) oprintf(" (end)\n");
+ if (cnt != (int64_t)map.count()) {
+ errprint(__LINE__, "LinkedHashMap::count");
+ err = true;
+ }
+ cnt = 0;
+ Map::Iterator it = map.end();
+ while (!err && it != map.begin()) {
+ --it;
+ cnt++;
+ if (it.key() != it.value()) {
+ errprint(__LINE__, "LinkedHashMap::Iterator::key");
+ err = true;
+ }
+ if (rnum > 250 && cnt % (rnum / 250) == 0) {
+ oputchar('.');
+ if (cnt == rnum || cnt % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt);
+ }
+ }
+ if (rnd) oprintf(" (end)\n");
+ if (cnt != (int64_t)map.count()) {
+ errprint(__LINE__, "LinkedHashMap::count");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ }
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform thmap command
+static int32_t procthmap(int64_t rnum, bool rnd, int64_t bnum) {
+ oprintf("<Memory-saving Hash Map Test>\n seed=%u rnum=%lld rnd=%d bnum=%lld\n\n",
+ g_randseed, (long long)rnum, rnd, (long long)bnum);
+ bool err = false;
+ if (bnum < 0) bnum = 0;
+ kc::TinyHashMap map(bnum);
+ oprintf("setting records:\n");
+ double stime = kc::time();
+ for (int64_t i = 1; i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ map.set(kbuf, ksiz, kbuf, ksiz);
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ int64_t musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("getting records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ size_t vsiz;
+ const char* vbuf = map.get(kbuf, ksiz, &vsiz);
+ if (!vbuf && !rnd) {
+ errprint(__LINE__, "TinyHashMap::get: %s", kbuf);
+ err = true;
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("appending records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ map.append(kbuf, ksiz, kbuf, ksiz);
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("traversing records:\n");
+ stime = kc::time();
+ int64_t cnt = 0;
+ kc::TinyHashMap::Iterator it(&map);
+ const char* kbuf, *vbuf;
+ size_t ksiz, vsiz;
+ while ((kbuf = it.get(&ksiz, &vbuf, &vsiz)) != NULL) {
+ cnt++;
+ it.step();
+ if (rnum > 250 && cnt % (rnum / 250) == 0) {
+ oputchar('.');
+ if (cnt == rnum || cnt % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt);
+ }
+ }
+ if (rnd) oprintf(" (end)\n");
+ if (cnt != (int64_t)map.count()) {
+ errprint(__LINE__, "TinyHashMap::count");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("sorting records:\n");
+ stime = kc::time();
+ cnt = 0;
+ kc::TinyHashMap::Sorter sorter(&map);
+ while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) {
+ cnt++;
+ sorter.step();
+ if (rnum > 250 && cnt % (rnum / 250) == 0) {
+ oputchar('.');
+ if (cnt == rnum || cnt % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt);
+ }
+ }
+ if (rnd) oprintf(" (end)\n");
+ if (cnt != (int64_t)map.count()) {
+ errprint(__LINE__, "TinyHashMap::count");
+ err = true;
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("removing records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd ? myrand(rnum) + 1 : i));
+ if (!map.remove(kbuf, ksiz) && !rnd) {
+ errprint(__LINE__, "TinyHashMap::remove: %s", kbuf);
+ err = true;
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ if (rnd) {
+ oprintf("wicked testing:\n");
+ stime = kc::time();
+ char lbuf[RECBUFSIZL];
+ std::memset(lbuf, '*', sizeof(lbuf));
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ char kbuf[RECBUFSIZ];
+ size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(rnum) + 1));
+ size_t vsiz = myrand(sizeof(lbuf));
+ switch (myrand(6)) {
+ case 0: {
+ map.set(kbuf, ksiz, lbuf, vsiz);
+ break;
+ }
+ case 1: {
+ map.add(kbuf, ksiz, lbuf, vsiz);
+ break;
+ }
+ case 2: {
+ map.replace(kbuf, ksiz, lbuf, vsiz);
+ break;
+ }
+ case 3: {
+ map.append(kbuf, ksiz, lbuf, vsiz);
+ break;
+ }
+ case 6: {
+ map.remove(kbuf, ksiz);
+ break;
+ }
+ default: {
+ map.get(kbuf, ksiz, &vsiz);
+ break;
+ }
+ }
+ if (myrand(rnum * 2 + 1) == 0) map.clear();
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)map.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ }
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform talist command
+static int32_t proctalist(int64_t rnum, bool rnd) {
+ oprintf("<Memory-saving Array List Test>\n seed=%u rnum=%lld rnd=%d\n\n",
+ g_randseed, (long long)rnum, rnd);
+ bool err = false;
+ kc::TinyArrayList list;
+ oprintf("setting records:\n");
+ double stime = kc::time();
+ for (int64_t i = 1; i <= rnum; i++) {
+ char buf[RECBUFSIZ];
+ size_t size = std::sprintf(buf, "%08lld", (long long)i);
+ if (rnd && myrand(2) == 0) {
+ list.unshift(buf, size);
+ } else {
+ list.push(buf, size);
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ double etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)list.count());
+ int64_t musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("getting records:\n");
+ stime = kc::time();
+ size_t cnt = list.count();
+ for (int64_t i = 1; i <= rnum; i++) {
+ size_t size;
+ list.get(rnd ? myrand(cnt) : i - 1, &size);
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)list.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ oprintf("removing records:\n");
+ stime = kc::time();
+ for (int64_t i = 1; i <= rnum; i++) {
+ if (rnd && myrand(2) == 0) {
+ list.shift();
+ } else {
+ list.pop();
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)list.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ if (rnd) {
+ oprintf("wicked testing:\n");
+ stime = kc::time();
+ char lbuf[RECBUFSIZL];
+ std::memset(lbuf, '*', sizeof(lbuf));
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ size_t size = myrand(sizeof(lbuf));
+ cnt = list.count();
+ switch (myrand(10)) {
+ case 0: {
+ list.pop();
+ break;
+ }
+ case 1: {
+ list.unshift(lbuf, size);
+ break;
+ }
+ case 2: {
+ list.shift();
+ break;
+ }
+ case 3: {
+ list.insert(lbuf, size, cnt > 0 ? myrand(cnt) : 0);
+ break;
+ }
+ case 4: {
+ if (cnt > 0) list.remove(myrand(cnt));
+ break;
+ }
+ case 5: {
+ if (cnt > 0) list.get(myrand(cnt), &size);
+ break;
+ }
+ case 6: {
+ if (myrand(100) == 0) list.clear();
+ break;
+ }
+ default: {
+ list.push(lbuf, size);
+ break;
+ }
+ }
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ etime = kc::time();
+ oprintf("time: %.3f\n", etime - stime);
+ oprintf("count: %lld\n", (long long)list.count());
+ musage = memusage();
+ if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
+ }
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+// perform misc command
+static int32_t procmisc(int64_t rnum) {
+ oprintf("<Miscellaneous Test>\n seed=%u rnum=%lld\n\n", g_randseed, (long long)rnum);
+ bool err = false;
+ if (!kc::_dummytest()) {
+ errprint(__LINE__, "_dummytest");
+ err = true;
+ }
+ double stime = kc::time();
+ for (int64_t i = 1; !err && i <= rnum; i++) {
+ uint16_t num16 = (1ULL << myrand(sizeof(num16) * 8)) - 5 + myrand(10);
+ uint32_t num32 = (1ULL << myrand(sizeof(num32) * 8)) - 5 + myrand(10);
+ uint64_t num64 = (1ULL << myrand(sizeof(num64) * 8)) - 5 + myrand(10);
+ if (kc::ntoh16(kc::hton16(num16)) != num16) {
+ errprint(__LINE__, "ntoh16: %llu", (unsigned long long)num16);
+ err = true;
+ }
+ if (kc::ntoh32(kc::hton32(num32)) != num32) {
+ errprint(__LINE__, "ntoh32: %llu", (unsigned long long)num32);
+ err = true;
+ }
+ if (kc::ntoh64(kc::hton64(num64)) != num64) {
+ errprint(__LINE__, "ntoh64: %llu", (unsigned long long)num64);
+ err = true;
+ }
+ char fbuf[sizeof(num64)];
+ num64 = (uint64_t)myrand(kc::INT32MAX) * myrand(kc::INT16MAX);
+ kc::writefixnum(fbuf, num64, 6);
+ uint64_t onum = kc::readfixnum(fbuf, 6);
+ if (onum != num64) {
+ errprint(__LINE__, "readfixnum: %llu:%llu",
+ (unsigned long long)num64, (unsigned long long)onum);
+ err = true;
+ }
+ unsigned char ubuf[RECBUFSIZ];
+ unsigned char* uwp = ubuf;
+ if (kc::writevarnum(uwp, num32) != kc::sizevarnum(num32)) {
+ errprint(__LINE__, "sizevarnum: %llu", (unsigned long long)num32);
+ err = true;
+ }
+ uwp += kc::writevarnum(uwp, num16);
+ uwp += kc::writevarnum(uwp, num32);
+ uwp += kc::writevarnum(uwp, num64);
+ const unsigned char* urp = ubuf;
+ urp += kc::readvarnum(urp, uwp - urp, &onum);
+ if (onum != num16) {
+ errprint(__LINE__, "readvarnum: %llu:%llu",
+ (unsigned long long)num16, (unsigned long long)onum);
+ err = true;
+ }
+ urp += kc::readvarnum(urp, uwp - urp, &onum);
+ if (onum != num32) {
+ errprint(__LINE__, "readvarnum: %llu:%llu",
+ (unsigned long long)num32, (unsigned long long)onum);
+ err = true;
+ }
+ urp += kc::readvarnum(urp, uwp - urp, &onum);
+ if (onum != num64) {
+ errprint(__LINE__, "readvarnum: %llu:%llu",
+ (unsigned long long)num64, (unsigned long long)onum);
+ err = true;
+ }
+ if (urp != uwp) {
+ errprint(__LINE__, "readvarnum: %d", (int)(uwp - urp));
+ err = true;
+ }
+ size_t usiz = urp - ubuf;
+ uint64_t hash = kc::hashmurmur(&num16, sizeof(num16)) + kc::hashmurmur(ubuf, usiz);
+ hash += kc::hashfnv(&num16, sizeof(num16)) + kc::hashfnv(ubuf, usiz);
+ char name[kc::NUMBUFSIZ];
+ hash += kc::hashpath(ubuf, usiz, name);
+ hash = kc::nearbyprime(myrand(kc::INT32MAX));
+ if (myrand(256) == 0) {
+ int32_t unum = myrand(64);
+ std::vector<uint32_t> oucs;
+ for (int32_t j = 0; j < unum; j++) {
+ uint32_t c = std::pow(2, myrand(31000000) / 1000000.0);
+ oucs.push_back(c);
+ }
+ std::string utf;
+ kc::strucstoutf(oucs, &utf);
+ std::vector<uint32_t> nucs;
+ kc::strutftoucs(utf, &nucs);
+ if (nucs.size() == oucs.size()) {
+ for (int32_t j = 0; j < (int32_t)nucs.size(); j++) {
+ if (nucs[j] != oucs[j]) {
+ errprint(__LINE__, "strutftoucs: %d:%d", (int)nucs[j], (int)oucs[j]);
+ err = true;
+ break;
+ }
+ }
+ } else {
+ errprint(__LINE__, "strutftoucs: %d:%d", (int)nucs.size(), (int)oucs.size());
+ err = true;
+ }
+ uint32_t* cucs = new uint32_t[utf.size()+1];
+ size_t cucsnum;
+ if (myrand(2) == 0) {
+ kc::strutftoucs(utf.c_str(), cucs, &cucsnum);
+ } else {
+ kc::strutftoucs(utf.data(), utf.size(), cucs, &cucsnum);
+ }
+ if (cucsnum == oucs.size()) {
+ char* cutf = new char[cucsnum*6+1];
+ kc::strucstoutf(cucs, cucsnum, cutf);
+ if (std::strcmp(cutf, utf.c_str())) {
+ errprint(__LINE__, "strucstoutf");
+ err = true;
+ }
+ delete[] cutf;
+ } else {
+ errprint(__LINE__, "strutftoucs");
+ err = true;
+ }
+ delete[] cucs;
+ int32_t tnum = myrand(64);
+ std::vector<std::string> ovec;
+ std::map<std::string, std::string> omap;
+ for (int32_t j = 0; j < tnum; j++) {
+ char kbuf[RECBUFSIZ];
+ std::sprintf(kbuf, "%lld", (long long)myrand(rnum));
+ char vbuf[RECBUFSIZ];
+ std::sprintf(vbuf, "%lld", (long long)myrand(rnum));
+ ovec.push_back(vbuf);
+ omap[kbuf] = vbuf;
+ }
+ std::string vstr;
+ kc::strvecdump(ovec, &vstr);
+ std::vector<std::string> nvec;
+ kc::strvecload(vstr, &nvec);
+ if (nvec.size() != ovec.size()) {
+ errprint(__LINE__, "strvecload: %d:%d", (int)nvec.size(), (int)ovec.size());
+ err = true;
+ }
+ std::string mstr;
+ kc::strmapdump(omap, &mstr);
+ std::map<std::string, std::string> nmap;
+ kc::strmapload(mstr, &nmap);
+ if (nmap.size() != omap.size()) {
+ errprint(__LINE__, "strmapload: %d:%d", (int)nvec.size(), (int)ovec.size());
+ err = true;
+ }
+ }
+ char* ebuf = kc::hexencode(ubuf, usiz);
+ size_t osiz;
+ char* obuf = kc::hexdecode(ebuf, &osiz);
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "hexencode: %d:%d", (int)osiz, (int)usiz);
+ err = true;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ ebuf = kc::urlencode(ubuf, usiz);
+ obuf = kc::urldecode(ebuf, &osiz);
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "urlencode: %d:%d", (int)osiz, (int)usiz);
+ err = true;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ ebuf = kc::quoteencode(ubuf, usiz);
+ obuf = kc::quotedecode(ebuf, &osiz);
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "quoteencode: %d:%d", (int)osiz, (int)usiz);
+ err = true;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ ebuf = kc::baseencode(ubuf, usiz);
+ obuf = kc::basedecode(ebuf, &osiz);
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "baseencode: %d:%d", (int)osiz, (int)usiz);
+ err = true;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ size_t nsiz = std::strlen(name);
+ nsiz -= i % nsiz;
+ ebuf = new char[usiz];
+ kc::arccipher(ubuf, usiz, name, nsiz, ebuf);
+ obuf = new char[usiz];
+ kc::arccipher(ebuf, usiz, name, nsiz, obuf);
+ if (std::memcmp(obuf, ubuf, usiz)) {
+ errprint(__LINE__, "arccipher: %s", name);
+ err = true;
+ }
+ if (kc::memicmp(obuf, ubuf, usiz)) {
+ errprint(__LINE__, "memicmp");
+ err = true;
+ }
+ if (!kc::memmem(obuf, osiz, ubuf, usiz)) {
+ errprint(__LINE__, "memmem");
+ err = true;
+ }
+ if (!kc::memimem(obuf, osiz, ubuf, usiz)) {
+ errprint(__LINE__, "memimem");
+ err = true;
+ }
+ if (kc::memdist(obuf, osiz, ubuf, usiz)) {
+ errprint(__LINE__, "memdist");
+ err = true;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ ebuf = kc::memdup((char*)ubuf, usiz);
+ ebuf[usiz] = '\0';
+ obuf = kc::strdup(ebuf);
+ switch (myrand(18)) {
+ case 0: kc::atoi(obuf); break;
+ case 1: kc::atoix(obuf); break;
+ case 2: kc::atoih(obuf); break;
+ case 3: kc::atoin((char*)ubuf, usiz); break;
+ case 4: kc::atof(obuf); break;
+ case 5: kc::atofn((char*)ubuf, usiz); break;
+ case 6: kc::strtoupper(obuf); break;
+ case 7: kc::strtolower(obuf); break;
+ case 8: kc::strtrim(obuf); break;
+ case 9: kc::strsqzspc(obuf); break;
+ case 10: kc::strnrmspc(obuf); break;
+ case 11: kc::stricmp(obuf, ebuf); break;
+ case 12: kc::stristr(obuf, ebuf); break;
+ case 13: kc::strfwm(obuf, ebuf); break;
+ case 14: kc::strifwm(obuf, ebuf); break;
+ case 15: kc::strbwm(obuf, ebuf); break;
+ case 16: kc::stribwm(obuf, ebuf); break;
+ case 17: kc::strutflen(obuf); break;
+ }
+ delete[] obuf;
+ delete[] ebuf;
+ kc::ZLIB::Mode zmode;
+ switch (myrand(3)) {
+ default: zmode = kc::ZLIB::RAW; break;
+ case 0: zmode = kc::ZLIB::DEFLATE; break;
+ case 1: zmode = kc::ZLIB::GZIP; break;
+ }
+ size_t zsiz;
+ char* zbuf = kc::ZLIB::compress(ubuf, usiz, &zsiz, zmode);
+ if (zbuf) {
+ obuf = kc::ZLIB::decompress(zbuf, zsiz, &osiz, zmode);
+ if (obuf) {
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "ZLIB::decompress");
+ err = true;
+ }
+ delete[] obuf;
+ } else {
+ errprint(__LINE__, "ZLIB::decompress");
+ err = true;
+ }
+ delete[] zbuf;
+ } else {
+ errprint(__LINE__, "ZLIB::compress");
+ err = true;
+ }
+ zbuf = kc::LZO::compress(ubuf, usiz, &zsiz);
+ if (zbuf) {
+ obuf = kc::LZO::decompress(zbuf, zsiz, &osiz);
+ if (obuf) {
+ if (osiz != usiz || std::memcmp(obuf, ubuf, osiz)) {
+ errprint(__LINE__, "LZO::decompress");
+ err = true;
+ }
+ delete[] obuf;
+ } else {
+ errprint(__LINE__, "LZO::decompress");
+ err = true;
+ }
+ delete[] zbuf;
+ } else {
+ errprint(__LINE__, "LZO::compress");
+ err = true;
+ }
+ std::string ustr((char*)ubuf, usiz);
+ kc::Regex::match(ustr, ".(\x80).");
+ kc::Regex::replace(ustr, ".(\x80).", "[$0$1$2$&]");
+ if (rnum > 250 && i % (rnum / 250) == 0) {
+ oputchar('.');
+ if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
+ }
+ }
+ oprintf("time: %.3f\n", kc::time() - stime);
+ oprintf("%s\n\n", err ? "error" : "ok");
+ return err ? 1 : 0;
+}
+
+
+
+// END OF FILE