benchmarks icon indicating copy to clipboard operation
benchmarks copied to clipboard

c++ for bench.b could be implemented 20% faster for x64 and twice faster for x86

Open guffy1234 opened this issue 5 years ago • 2 comments

numbers are with disabled print

namespace modified
{
	enum op_type {
		INC,
		MOVE,
		LOOP,
		PRINT
	};

	struct Op;
	using Ops = vector<Op>;

	using data_t = ptrdiff_t;

	struct Op
	{
		op_type op;
		data_t val;
		Ops loop;
		Op(Ops v) : op(LOOP), loop(v) {}
		Op(op_type _op, data_t v = 0) : op(_op), val(v) {}
	};

	class Tape
	{
		using vect = vector<data_t>;
		vect	tape;
		vect::iterator	pos;
	public:
		Tape()
		{
			tape.reserve(8);
			tape.push_back(0);
			pos = tape.begin();
		}

		inline data_t get() const
		{
			return *pos;
		}
		inline void inc(data_t x)
		{
			*pos += x;
		}
		inline void move(data_t x)
		{
			auto d = std::distance(tape.begin(), pos);
			d += x;
			if (d >= (data_t)tape.size())
				tape.resize(d + 1);
			pos = tape.begin();
			std::advance(pos, d);
		}
	};

	class Program
	{
		Ops ops;
	public:
		Program(const string& code)
		{
			auto iterator = code.cbegin();
			ops = parse(&iterator, code.cend());
		}

		void run() const
		{
			Tape tape;
			_run(ops, tape);
		}
	private:
		static Ops parse(string::const_iterator *iterator, string::const_iterator end)
		{
			Ops res;
			while (*iterator != end)
			{
				char c = **iterator;
				*iterator += 1;
				switch (c) {
				case '+':
					res.emplace_back(INC, 1);
					break;
				case '-':
					res.emplace_back(INC, -1);
					break;
				case '>':
					res.emplace_back(MOVE, 1);
					break;
				case '<':
					res.emplace_back(MOVE, -1);
					break;
				case '.':
					res.emplace_back(PRINT);
					break;
				case '[':
					res.emplace_back(parse(iterator, end));
					break;
				case ']':
					return res;
				}
			}
			return res;
		}

		static void _run(const Ops &program, Tape &tape)
		{
			for (auto &op : program)
			{
				switch (op.op) 
				{
				case INC:
					tape.inc(op.val);
					break;
				case MOVE:
					tape.move(op.val);
					break;
				case LOOP:
					while (tape.get() > 0)
						_run(op.loop, tape);
					break;
				case PRINT:
					if (do_print())
					{
						printf("%c", (int)tape.get());
						fflush(stdout);
					}
					break;
				}
			}
		}
	};
}

bf2_bench.zip x86 x64

guffy1234 avatar Jan 25 '19 12:01 guffy1234

not really see what changed, seems parse method, this not in main loop so it unimportant. move method also called only to size 8

kostya avatar Jan 25 '19 13:01 kostya

almost all changes was made to make just good modern c++ style. most important from performance point of view for this test is avoid to pointer arithmetic in every get()/inc() (using *pos instead of tape[pos]) also _run method does't need "this" so it could be static member and doesn't require to put hidden "this" argument

guffy1234 avatar Jan 25 '19 14:01 guffy1234