Blame projects/neural/common.inc.cpp

Ivan Mahonin b579b3
#ifndef COMMON_INC_CPP
Ivan Mahonin b579b3
#define COMMON_INC_CPP
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
#include <cmath>
Ivan Mahonin b579b3
#include <cstdio>
Ivan Mahonin b579b3
#include <cstdlib>
Ivan Mahonin b579b3
#include <cstring>
Ivan Mahonin b579b3
#include <cassert>
Ivan Mahonin b579b3
Ivan Mahonin b579b3
#include <atomic>
Ivan Mahonin b579b3
#include <vector>
Ivan Mahonin b579b3
#include <string>
Ivan Mahonin b579b3
#include <chrono>
Ivan Mahonin b579b3
#include <algorithm>
Ivan Mahonin b579b3
Ivan Mahonin e4740d
#include <mutex>
Ivan Mahonin e4740d
#include <thread>
Ivan Mahonin e4740d
#include <condition_variable>
Ivan Mahonin e4740d
Ivan Mahonin b579b3
Ivan Mahonin b579b3
#include "layout.inc.cpp"
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
typedef double WeightReal;
Ivan Mahonin b579b3
typedef double NeuronReal;
Ivan Mahonin b579b3
typedef double AccumReal;
Ivan Mahonin b579b3
Ivan Mahonin b579b3
typedef int WeightInt;
Ivan Mahonin b579b3
typedef int AccumInt;
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
#define RANDOM_MAX 0x7fffffff
Ivan Mahonin b579b3
inline unsigned int randomNext(unsigned int prev)
Ivan Mahonin b579b3
  { return (1103515245*prev + 12345) & RANDOM_MAX; }
Ivan Mahonin b579b3
inline unsigned int randomBranch(unsigned int seed)
Ivan Mahonin b579b3
  { return randomNext(seed + 1); }
Ivan Mahonin b579b3
  
Ivan Mahonin b579b3
inline void busyloop(unsigned int count)
Ivan Mahonin b579b3
  { while(count--) __asm__ __volatile__(""); }
Ivan Mahonin e4740d
inline void sleep()
Ivan Mahonin e4740d
  { std::this_thread::sleep_for(std::chrono::nanoseconds(0)); }
Ivan Mahonin e4740d
inline void sleepUs(long long us)
Ivan Mahonin e4740d
  { std::this_thread::sleep_for(std::chrono::microseconds(us)); }
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
inline long long timeUs() {
Ivan Mahonin b579b3
  static std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
Ivan Mahonin b579b3
  return (long long)std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::steady_clock::now() - begin ).count();
Ivan Mahonin b579b3
}
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  
Ivan Mahonin b579b3
struct Accum {
Ivan Mahonin b579b3
  union { AccumReal v; AccumInt i; };
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
struct Neuron {
Ivan Mahonin b579b3
  NeuronReal v, d;
Ivan Mahonin b579b3
  Accum a;
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
struct Weight {
Ivan Mahonin b579b3
  union { WeightReal w; WeightInt i; };
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
struct Iter {
Ivan Mahonin b579b3
  typedef Accum AccumType;
Ivan Mahonin b579b3
  typedef NeuronReal* DataType;
Ivan Mahonin b579b3
  typedef AccumType DataAccumType;
Ivan Mahonin b579b3
  static inline void init(Neuron&, AccumType&) { }
Ivan Mahonin b579b3
  static inline void iter(Neuron&, Weight&, AccumType&) { }
Ivan Mahonin b579b3
  static inline void done(Neuron&, AccumType&) { }
Ivan Mahonin b579b3
  static inline void iter2(Neuron&, Neuron&, Weight&) { }
Ivan Mahonin b579b3
  static inline void iter3(Neuron&) { }
Ivan Mahonin b579b3
  static inline void iter4(Neuron&, DataType, DataAccumType&) { }
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin e4740d
class Barrier;
Ivan Mahonin e4740d
Ivan Mahonin e4740d
class ThreadControl {
Ivan Mahonin e4740d
private:
Ivan Mahonin e4740d
  friend class Barrier;
Ivan Mahonin e4740d
  
Ivan Mahonin e4740d
  std::mutex mutex;
Ivan Mahonin e4740d
  std::condition_variable cond;
Ivan Mahonin e4740d
  std::atomic<unsigned int> counter;
Ivan Mahonin e4740d
  std::vector<std::thread*> threads;
Ivan Mahonin e4740d
  unsigned int commonSeed;
Ivan Mahonin e4740d
  
Ivan Mahonin e4740d
  void runSingleThread(unsigned int tid, unsigned int seed);
Ivan Mahonin e4740d
Ivan Mahonin e4740d
protected:
Ivan Mahonin e4740d
  virtual void threadFunc(Barrier&) { }
Ivan Mahonin e4740d
  
Ivan Mahonin e4740d
public:
Ivan Mahonin e4740d
  ThreadControl(): counter(0), commonSeed() { }
Ivan Mahonin e4740d
  void runThreads(unsigned int threadsCount = 1) {
Ivan Mahonin e4740d
    assert(threadsCount);
Ivan Mahonin e4740d
    counter = 0;
Ivan Mahonin e4740d
    threads.clear();
Ivan Mahonin e4740d
    threads.resize(threadsCount);
Ivan Mahonin e4740d
    commonSeed = rand();
Ivan Mahonin e4740d
    for(unsigned int i = 1; i < threadsCount; ++i)
Ivan Mahonin e4740d
      threads[i] = new std::thread(&ThreadControl::runSingleThread, this, i, rand());
Ivan Mahonin e4740d
    runSingleThread(0, rand());
Ivan Mahonin e4740d
    for(unsigned int i = 1; i < threadsCount; ++i)
Ivan Mahonin e4740d
      { threads[i]->join(); delete threads[i]; }
Ivan Mahonin e4740d
    threads.clear();
Ivan Mahonin e4740d
  }
Ivan Mahonin e4740d
};
Ivan Mahonin e4740d
Ivan Mahonin e4740d
Ivan Mahonin b579b3
class Barrier {
Ivan Mahonin b579b3
private:
Ivan Mahonin e4740d
  ThreadControl &owner;
Ivan Mahonin b579b3
  unsigned int next;
Ivan Mahonin b579b3
  unsigned int busyseed;
Ivan Mahonin b579b3
public:
Ivan Mahonin b579b3
  const unsigned int tid;
Ivan Mahonin b579b3
  const unsigned int threads;
Ivan Mahonin b579b3
  unsigned int seed;
Ivan Mahonin e4740d
  unsigned int commonSeed;
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  Barrier(const Barrier&) = delete;
Ivan Mahonin e4740d
  inline Barrier(ThreadControl &owner, unsigned int tid, unsigned int seed, unsigned int commonSeed):
Ivan Mahonin e4740d
    owner(owner), next(), busyseed(randomBranch(seed)), tid(tid), threads(owner.threads.size()), seed(seed), commonSeed(commonSeed)
Ivan Mahonin e4740d
    { assert(tid < threads); }
Ivan Mahonin b579b3
    
Ivan Mahonin b579b3
  //inline void busyloop() { }
Ivan Mahonin b579b3
  inline void busyloop(unsigned int maxCycles = 4096) { ::busyloop( (busyseed = randomNext(busyseed))%maxCycles ); }
Ivan Mahonin b579b3
  inline unsigned int rand() { return seed = randomNext(seed); }
Ivan Mahonin e4740d
  inline unsigned int commonRand() { return commonSeed = randomNext(commonSeed); }
Ivan Mahonin e4740d
  inline void wait() { next += threads; ++owner.counter; while(owner.counter < next) busyloop(); }
Ivan Mahonin e4740d
  inline void subwait() { while(owner.counter < next + tid) busyloop(); }
Ivan Mahonin e4740d
  
Ivan Mahonin e4740d
  inline void wait2() {
Ivan Mahonin e4740d
    next += threads;
Ivan Mahonin e4740d
    std::unique_lock<std::mutex> lock(owner.mutex);
Ivan Mahonin e4740d
    if (++owner.counter == next) owner.cond.notify_all(); else
Ivan Mahonin e4740d
      while(owner.counter < next) owner.cond.wait(lock);
Ivan Mahonin e4740d
  }
Ivan Mahonin b579b3
  
Ivan Mahonin e4740d
  inline void wait3() { next += threads; ++owner.counter; while(owner.counter < next) sleepUs(1); }
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin e4740d
void ThreadControl::runSingleThread(unsigned int tid, unsigned int seed) {
Ivan Mahonin e4740d
  Barrier barrier(*this, tid, seed, commonSeed);
Ivan Mahonin e4740d
  threadFunc(barrier);
Ivan Mahonin e4740d
}
Ivan Mahonin e4740d
Ivan Mahonin e4740d
Ivan Mahonin e4740d
Ivan Mahonin b579b3
struct Stat {
Ivan Mahonin b579b3
  int neurons;
Ivan Mahonin b579b3
  int activeNeurons;
Ivan Mahonin b579b3
  int weights;
Ivan Mahonin b579b3
  int links;
Ivan Mahonin b579b3
  size_t memsize;
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  Stat(): neurons(), activeNeurons(), weights(), links(), memsize() { }
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  Stat& operator+= (const Stat &b) {
Ivan Mahonin b579b3
    neurons += b.neurons;
Ivan Mahonin b579b3
    activeNeurons += b.activeNeurons;
Ivan Mahonin b579b3
    weights += b.weights;
Ivan Mahonin b579b3
    links   += b.links;
Ivan Mahonin b579b3
    memsize += b.memsize;
Ivan Mahonin b579b3
    return *this;
Ivan Mahonin b579b3
  }
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  void print(const char *prefix = nullptr) const {
Ivan Mahonin b579b3
    if (prefix && *prefix) printf("%s: ", prefix);
Ivan Mahonin b579b3
    printf("neurons: %d / %d, links %d / %d, memSize: %llu\n", activeNeurons, neurons, weights, links, (unsigned long long)memsize);
Ivan Mahonin b579b3
  }
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
struct Quality {
Ivan Mahonin b579b3
  AccumReal train;
Ivan Mahonin b579b3
  AccumReal human;
Ivan Mahonin b579b3
  
Ivan Mahonin b579b3
  inline Quality(AccumReal train, AccumReal human): train(train), human(human) {}
Ivan Mahonin b579b3
  inline explicit Quality(AccumReal train = 0): Quality(train, train) {}
Ivan Mahonin b579b3
  inline static Quality nan() { return Quality(NAN); }
Ivan Mahonin b579b3
  inline static Quality bad() { return Quality(INFINITY); }
Ivan Mahonin b579b3
  
Ivan Mahonin b579b3
  inline Quality& operator+=(const Quality &b)
Ivan Mahonin b579b3
    { train += b.train; human += b.human; return *this; }
Ivan Mahonin b579b3
  inline Quality& operator*=(AccumReal x)
Ivan Mahonin b579b3
    { train *= x; human *= x; return *this; }
Ivan Mahonin b579b3
  inline bool operator<(const Quality &b) const {
Ivan Mahonin b579b3
    return human < b.human ? true
Ivan Mahonin b579b3
         : b.human < human ? false
Ivan Mahonin b579b3
         : train < b.train;
Ivan Mahonin b579b3
  }
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
struct QualityPair {
Ivan Mahonin b579b3
  Quality measure;
Ivan Mahonin b579b3
  Quality train;
Ivan Mahonin b579b3
  
Ivan Mahonin b579b3
  inline explicit QualityPair(const Quality &measure = Quality(), const Quality &train = Quality()):
Ivan Mahonin b579b3
    measure(measure), train(train) { }
Ivan Mahonin b579b3
Ivan Mahonin b579b3
  inline QualityPair& operator+=(const QualityPair &b)
Ivan Mahonin b579b3
    { measure += b.measure; train += b.train; return *this; }
Ivan Mahonin b579b3
  inline QualityPair& operator*=(AccumReal x)
Ivan Mahonin b579b3
    { measure *= x; train *= x; return *this; }
Ivan Mahonin b579b3
  inline bool operator<(const QualityPair &b) const {
Ivan Mahonin b579b3
    return measure < b.measure ? true
Ivan Mahonin b579b3
         : b.measure < measure ? false
Ivan Mahonin b579b3
         : train < b.train;
Ivan Mahonin b579b3
  }
Ivan Mahonin b579b3
};
Ivan Mahonin b579b3
Ivan Mahonin b579b3
Ivan Mahonin b579b3
#endif
Ivan Mahonin b579b3