refactor cudaEvent usage

- add `CudaEvent` which is a wrapper for cudaEvent_t
- solve problem that `cudaStreamWaitEvent` was called to often
- EventStream: add function `waitOn(CudaEvent)`

This pull request minimize the overhead of the event system. (~ 3-5%)
Should we guard against double-records without polling (`isFinished`) in between? e.g. set `isRecorded` to false if `ifFinished` returns true