Archive

Author Archive

From Daily Standup To Daily Inquisition

September 23, 2016 Leave a comment
Categories: management Tags: ,

Advice That Transcends Time

September 10, 2016 2 comments

Please take a moment to temporarily push all you’ve learned about large-system software development on the stack in your brain and imbibe some timeless advice from this thoughtful, 1992, NASA report: “Recommended Approach To Software Development“:

timelessadvice

Ok, now that you’re done processing what you’ve just seen, you can pop the stack.

 

Move In, Move Out

August 14, 2016 2 comments

In many application domains, the Producer-Queue-Consumer pattern is used to transport data from input to output within a multi-threaded program:

producerconsumer

The ProducerThread creates Messages in accordance with the application’s requirements and pushes pointers to them into a lock-protected queue. The ConsumerThread, running asynchronous to the ProducerThread, pops sequences of Message pointers from the queue and processes them accordingly. The ConsumerThread may be notified by the ProducerThread when one or more Messages are available for processing or it can periodically poll the queue.

Instead of passing Message pointers, Message copies can be passed between the threads. However, copying the content can be expensive for large messages.

When using pointers to pass messages between threads, the memory to hold the data content must come from somewhere. One way to provide this memory is to use a Message buffer pool allocated on startup.

MsgBufferPool

Another, simpler way that avoids the complexity of managing a Message buffer pool, is to manually “new” up the memory in the ProducerThread and then manually “delete” memory in the ConsumerThread.

newdelete

Since the introduction of smart pointers in C++11, a third way of communicating messages between threads is to “movestd::unique_ptrs into and out of the InterThreadQueue:

moveinmoveout

The advantage of using smart pointers is that no “deletes” need to be manually written in the ConsumerThread code.

The following code shows the implementation and usage of a simple InterThreadQueue that moves std::unique_ptrs into and out of a lock protected std::deque.

InterthreadQueueImpl

InterThreadQueueUsage

#include "catch.hpp"
#include <memory>
#include <deque>
#include <mutex>
#include <vector>
#include <stdexcept>

template<typename Msg>
class InterThreadQueue {
public:
  InterThreadQueue(int32_t capacity) :
    _capacity(capacity) {}

  void push(std::unique_ptr<Msg> msg) {
    std::lock_guard<std::mutex> lg(_mtx);
    if(_queue.size() not_eq _capacity) {
      _queue.push_back(std::move(msg));
    }
    else {
      throw std::runtime_error{"Capacity Exceeded"};
    }
  }

  std::vector<std::unique_ptr<Msg>> pop() {
    std::vector<std::unique_ptr<Msg>> msgs{};
    std::lock_guard<std::mutex> lg(_mtx);
    while(not _queue.empty()) {
      msgs.emplace_back(std::move(_queue.front()));
      _queue.pop_front();
    }
    return msgs; //Move the vector to the caller
  }

private:
  mutable std::mutex _mtx{};
  const std::size_t _capacity;
  std::deque<std::unique_ptr<Msg>> _queue;
};

TEST_CASE( "InterThreadQueue" ) {
  //Create our object under test
  InterThreadQueue<int32_t> itq{2};

  //Note: my compiler version doesn't have std::make_unique<T>()
  std::unique_ptr<int32_t> dataIn{new int32_t{5}};
  itq.push(std::move(dataIn));
  dataIn = std::unique_ptr<int32_t>{new int32_t{10}};
  itq.push(std::move(dataIn));

  dataIn = std::unique_ptr<int32_t>{new int32_t{15}};
  //Queue capacity is only 2
  REQUIRE_THROWS(itq.push(std::move(dataIn)));

  auto dataOut = itq.pop();
  REQUIRE(2 == dataOut.size());
  REQUIRE(5 == *dataOut[0]);
  REQUIRE(10 == *dataOut[1]);

  REQUIRE(0 == itq.pop().size());
}
Categories: C++ Tags: ,

Generating NaNs


Nanonano
While converting serialized double precision floating point numbers received in a datagram over a UDP socket into a native C++ double type, I kept getting NaN values (Not a Number) whenever I used the deserialized version of the number in a numeric computation. Of course, the problem turned out to be the well-known Endian” issue where one machine represents numbers internally in Big Endian format and the other uses Little Endian format.

Endians

One way of creating a NaN is by taking the square root of a negative number. Another way is to jumble up the bytes in a float or double such that an illegal bit pattern is produced. Uncompensated Endian mismatches between machines can easily produce illegal bit patterns that create NaNs. Note that NaNs are only an issue in the floating point types because every conceivable bit pattern stored in an integral type is always legal.

To prove just how easy it is to produce a NaN by jumbling up the bytes in a double, I wrote this little program that I’d like to share:

NanGen

Here is a fragment of the output from a typical program run:

NanOut

I was a little surprised at the low number of iterations it typically takes to produce a NaN, but that’s a good thing. If it takes millions of iterations, it may be hard to trace a bug back to a NaN problem.

For those who would try this program out, here is a copy-paste version of the code:

#include <cstdint>
#include <iostream>
#include <random>
#include <cmath>

int main() {
    //Determine the number of bytes in a double
	const int32_t numBytesInDouble{sizeof(double)};

	//Create a fixed-size buffer that holds the number of bytes
	//in a double
	int8_t buffer[numBytesInDouble];

    //Setup a random number generator to produce
    //a uniformly distributed int8_t value
    std::random_device rd{};
    std::mt19937 gen{rd()};
    std::uniform_int_distribution<int8_t> dis{-128, 127};

    //interpret the buffer as a double*
    const double* dp{reinterpret_cast<double*>(buffer)};
    int32_t count{-1};
    do{
      //fill our buffer with random valued bytes
      for(int32_t i=0; i<numBytesInDouble; ++i) {
        buffer[i] = dis(gen);
      }

      std::cout << *dp << "\n";
      ++count;
    }while(not std::isnan(*dp));

    std::cout << "count = " << count << "\n";
}
Categories: C++ Tags: ,

Simply Brilliant

Categories: bitcoin Tags:

Perfect And Real

July 9, 2016 2 comments

In the perfect Scrum world, software is developed over time in fixed-size (ΔT) time boxes where all the work planned for the sprint is completed within the timebox. Typically ΔT is chosen to be 2 or 4 weeks.

perfect scrum

If all the tasks allocated to a sprint during the planning meeting are accurately estimated (which never happens), and all the tasks are independent (which never happens), and any developer can perform any task at the same efficiency as any other developer (which never happens), then bingo – we have a perfect Scrum world.

However, in the real world (Scrum or non-Scrum), some (most?) tasks are interdependent, some tasks are underestimated, and some tasks are overestimated:

Real Scrum

Thus, specifying a fixed ΔT timebox size for every single sprint throughout the effort may not be a wise decision. Or is it?

Categories: management Tags: ,

To The Moon Alice!

June 18, 2016 1 comment

Using the information below as a reference point,

goldandbondmarketcaps

let’s do some rounding and truncating and assume the following:

  • The total market capitalization of gold is $10T
  • The total market capitalization of negative interest bonds is $10T

With 15M BTC in circulation, the current market capitalization of Bitcoin is around $10B. If (when?) Bitcoin eventually manages to steal just 10% of the market capitalization from each of those two assets, its market cap would balloon to $2T, resulting in a gain of 200X. Yepp, that’s “X” and not “%”.

Bitcoin’s current price per USD is around $750. Multiplying this price by 200 yields a new price of $150,000 per BTC.

Of course, the BTC price could collapse to $0 at any point in time. However, since its launch in 2009, it has been declared “dead” by various experts over 106 times – and still counting.

btcobits

If you’ve got $750 of play money laying around, fuggedaboud searching for the next Amazon/Apple/Google/Netflix to invest in and hoping that the esteemed management of your new investment doesn’t fuck up for a decade. Consider doing the following instead:

  1. Opening an account on a reputable Bitcoin exchange (I use coinbase.com (USD-to-BTC exchange fee of 1%)).
  2. Buying 1 Bitcoin
  3. Becoming your own bank and immediately moving your 1 BTC out of your online exchange wallet and into your own PC-based wallet (I use Electrum), or mobile phone-based wallet (I use Blockchain), or hardware-based wallet (I use Trezor).

If BTC collapses or (more likely) you screw up taking full personal control over your BTC, your maximum loss will be $750. However, your upside is “to the moon Alice!“.

alice

Categories: bitcoin Tags: , , ,
%d bloggers like this: