nsubtil / lift Goto Github PK
View Code? Open in Web Editor NEWA collection of parallel programming primitives for CPUs and GPUs
License: Other
A collection of parallel programming primitives for CPUs and GPUs
License: Other
The various functor types used in most parallel primitives should be documented somewhere. At a minimum, they should be doxygenated. It would be desirable to have an actual interface object definition as well, even in the absence of C++ concepts.
I was aware of what inclusive_scan was doing, but I was not sure how to implement/create a predicate object/functor based on the current documentation. It would be helpful to have improved documentation on inclusive_scan
Algorithms that involve stream compaction can often end up launching for_each calls of size zero. This triggers CUDA runtime errors today, since it generates an invalid launch configuration.
It's not clear what the right thing to do here would be.
One option is to have Lift ignore zero-sized for_each calls, either silently or with run-time warnings (which would probably require some sort of debug or diagnostics infrastructure).
Another option is to leave the code as-is and let the CUDA runtime throw errors. This is not as bad as it seems, since these are very easy to spot in cuda-gdb, but it might be nicer if Lift itself can flag such situations.
Three clean-up items for inclusive_scan:
It's not immediately obvious in which cases it's useful to have different input and output data types, nor is it obvious how that affects the implementation of the scan predicate function.
The right thing to do might be to just have a single data type for both input and output. Either we need to check that the underlying type for InputIterator and OutputIterator is the same, or (preferably) we need to modify inclusive_scan to only accept the same input and output iterator data types.
Predicate is really a binary operator. It would be good to rename it. This ties in with #13.
pointer::peek() is non-const, but is not supposed to allow modifying anything behind the pointer. It should be made const.
thread_local storage is unsupported on some versions(Mavericks at least) of mac.
Usage of the current implementation of METHOD_INSTANTIATE yields warnings from nvcc:
/Users/rapososn/snail/oc_calibration/oc_calibration.cu(35): warning: nonstandard conversion of pointer-to-member to a function pointer
Calling t_begin() on a const Lift pointer seems to return a const Thrust iterator to a non-const data type, which the compiler rightfully complains about.
The likely cause is that the const_thrust_iterator type is missing the const qualifier on the data type.
Debian Jessie shipped with CMake 3.0. This seems like a reasonable target to support.
Lift should be able to build with CMake 3.0. Right now it demands 3.2. Need to investigate what (if any) changes are required to lower the version requirements.
The pointer class has an operator() that acts as an alias for peek(). This seems problematic, as it can easily be mistaken for the constructor syntax in allocations.
This has already bitten people and should go away.
We need the ability to isolate tests into different sets within the test harness. The idea is to enable users to run only CPU tests or only "fast" tests during a run.
We'll need to hash out what this should look like, given that client code will need to define their own sets of tests.
Ensure that the vector of test names contains only unique names
FindCUDA.cmake seems to have an incredibly strong desire to add the CUDA toolkit include path to the very beginning of the list no matter what. This makes it hard to point both Lift as well as Lift client code at Lift's version of the Thrust toolkit.
This needs to be fixed somehow. Alternatives include:
The current suballocator has a lot of cruft left over from the original implementation that should be cleaned up.
The test harness functionality desperately needs a command line parser. We need to be able to do things such as:
The exact set of features that we'll implement on top of this is TBD, but they all require some way to receive runtime parameters, hence the need for a command line parser of some sort.
It seems the path to the generated liftest binary is wrong when Lift is used as a nested CMake project.
It would be useful to add the ability to measure throughput to Lift timers. This can be accomplished by expanding the existing timer API to keep a counter of the amount of data each step will process (which would have to be optional).
If that doesn't work, a separate class derived from timer that can track throughput is probably the next best option.
The timer class creates and destroys CUDA events every time it's started / stopped. CUDA events should be reused instead.
Lift GPU timers are "very stateful" and have a destructor with lots of side effects. This is proving problematic in several use cases. Firepony in particular seems to rely on host timers being copiable, which has forced a corresponding and hopefully temporary change in Lift to allow host timers to be copied (cuda timers remain uncopiable).
We should reconsider whether this is the best approach.
One possible alternative would be to rely on the Lift context to track timers and keep all non-POD data on that side, turning the timer object itself into a shallow handle to the actual timer. This also has the advantage of allowing CUDA timer objects to be pooled and reused on a per-GPU basis. The drawbacks are potential performance issues with starting/stopping timers, depending on how the timer vs. state approach is designed (start/stop may have to do an expensive names array lookup).
Having a mechanism where temporary storage for parallel primitives is managed automatically (and efficiently) under the covers by Lift would be very desirable.
This would require per-thread, per-device context to be tracked by Lift.
For code like this:
struct s my_var;
pointer<system, uint32> p = my_var;
lift generates a somewhat obscure syntax error. It would be nice to generate a better message via compile-time checks and static_assert() that checks that the input for operator=() (or other similar entrypoints) is indeed a pointer type;
This issue attempts to document the current inconsistencies in the lift::parallel API.
Some of the parallel operators take as input abstract iterator types. Others require pointers as input. It would be nice. The current status seems to be:
Similar to the issue above, some operators take in first and last iterators while others take in first iterators + a numerical length. This should be made uniform.
By convention, temp_storage is usually the last parameter. Except for reduce_by_key, where it isn't.
The output buffers for the pointer version of reduce-by-key are resized to match the input size, even though the output size is expected to be smaller. The original reasoning behind this was to avoid reallocations of client memory which might be reused across calls to reduce-by-key, but this seems confusing. It might be best to leave allocations up to the caller entirely.
Any change here will probably have to be reflected in other operators that implement similar behavior.
run-length-encode calls it's key iterator InputIterator. reduce-by-key calls it KeyIterator. This seems confusing and unnecessarily inconsistent.
run-length-encode seems to assume that the input and output key types are different. They probably can't be.
Because it outputs a well-defined quantity (integral length of the runs), it probably makes sense to restrict this to integral quantities if possible.
The current atomics interface only supports int32 and float atomics. This should be expanded to all suitable data types.
We're also missing test coverage for atomic operations.
The current LIFT_TEST_FUNC* macros generate objects whose names are directly based on the test name argument. This easily leads to naming conflicts.
We need to make these object names less likely to clash with any other names in the same namespace. Adding some sort of atypical prefix (e.g, '__generated_test_object' or something along those lines) would probably suffice.
It would be very useful to allow the suballocator to log what is happening in order to get a feel for how well it's behaving on any given workload.
There is existing code to do that by printing messages to the console (currently disabled). This would be a useful starting point, though we may need to add more information to the output.
The existing suballocator parameters are not tested on real-world cases and are likely ineffective. This issue tracks the effort to improve this situation.
One likely outcome is that we may split allocation sizes into buckets that are handled by different suballocator objects.
The way pointer::range() works is confusing --- range should take a start and end index instead.
The automated build system won't notify when there are warnings in the build. Since we're looking to be free of warnings, it's probably best to enable -Werror for automated builds to catch such issues ahead of time.
It can be desirable to allow code that uses Lift to be built with the host compiler directly. The obvious use case is a CPU-only project, but it can be beneficial for GPU projects as well to avoid the overhead of compiling through nvcc.
This will require some surgery to isolate everything related to Thrust from the host-only build.
It would be very useful if Lift could implement a common interface for various profiling annotation APIs (nvtx, vtune tasks).
For CUDA profiling in particular, it can be hard to tell which kernel is running given the extremely long names generated by the compiler for each kernel entry point.
Seen in Travis builds:
/home/travis/build/nsubtil/lift/lift/atomics_host.inl: In static member function static float lift::atomics<system>::add(float*, float) [with lift::target_system system = (lift::target_system)0u]: /home/travis/build/nsubtil/lift/lift/atomics_host.inl:56:111: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] __atomic_compare_exchange((volatile uint32 *)address, ^ /home/travis/build/nsubtil/lift/lift/atomics_host.inl:61:29: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] if (*((uint32 *)&expected) == *((uint32 *)&oldval)) ^ /home/travis/build/nsubtil/lift/lift/atomics_host.inl:61:57: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] if (*((uint32 *)&expected) == *((uint32 *)&oldval)) ^
Lift currently lift/test.h and lift/test/test.h header files. This arrangement is somewhat confusing.
In a more general sense, having duplicate header file names in different directories is probably best avoided.
I've seen code written where functions return a scoped_allocation that was defined inside the function itself. This is obviously dangerous and can never work.
We should investigate whether there's some way of disallowing this without removing the ability to do implicit conversion to allocation or pointer.
The current launch parameter calculation code has a tendency to fill up blocks rather than queuing up larger numbers of smaller blocks. In many instances this seems to lead to worse performance.
It would be best to try to come up with a strategy that tries to keep block size manageable. The usual rule of thumb of 128 threads/block being a good number for most cases would probably apply here.
All Lift memory containers and pointers use 32-bit addresses by default. We should add "large" versions of the same containers to perform 64-bit arithmetic instead.
Note that this implies modifying certain return types. E.g., a large_allocation + offset must yield a large_pointer, not a 32-bit pointer as it does today.
We'll need to track performance across a variety of operations. The test harness needs the ability to run benchmarks in addition to tests.
A benchmark would return some sort of performance metric, which would have to be output by the test harness in some way. The obvious performance metric to track is throughput, though we might need different metrics for different tests, so it would be useful to allow the test to specify what metric is being output.
Most of lift/memory/type_assignment_checks.h is no longer relevant. It is also inside a namespace that no longer makes sense to preserve.
Similar to #12, copy_if and copy_flagged could use some cleanup as well. It's unclear whether input and output should be different types and the predicate in copy_if needs documenting.
Additionally, it would be good to provide (Lift) pointer versions with implicit size.
Lift could use a few examples to document how the library should be used.
TEST_FUN_HD, TEST_REGISTER and friends should be renamed to reflect the fact that they come from the Lift test harness.
Prepending LIFT_ to all the names is probably enough.
Catch-all issue to document and track work required to add unit tests for Lift.
The current scheme of adding tests based on a function call that explicitly registers them can be replaced by static initialization of objects whose constructors will register the tests. This would go a long way towards cleaning up Lift test code.
It would be useful to support more than one version of the CUDA toolkit. Currently Lift seems to build with CUDA 7.0 and 7.5, but only 7.5 is actively tested.
This issue tracks the effort of creating a list of suitable CUDA toolkit versions and implementing automated build/test environments to track all supported versions.
Attempting to use std::fpclassify on code built through nvcc seems to generate errors like this:
/usr/include/c++/4.9/cmath(562): error: calling a host function("builtin_fpclassify") from a __device function("std::fpclassify") is not allowed
This happens even though the caller of std::fpclassify is undecorated (i.e., host only).
sort_test_cuda is showing failures as of commit dad6254
A number of tests based on Lift currently use their own built-in RNGs for simplicity and consistency across platforms. We should implement a single version in Lift.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.