1+ #include < thrust/device_ptr.h>
2+ #include < thrust/count.h>
3+ #include < thrust/execution_policy.h>
4+
5+ #include < iostream>
6+
7+ // ///////////////////////////////////////////////////////////////
8+ // Some utility code to define grid_stride_range
9+ // Normally this would be in a header but it's here
10+ // for didactic purposes. Uses
11+ #include " range.hpp"
12+ using namespace util ::lang;
13+
14+ // type alias to simplify typing...
15+ template <typename T>
16+ using step_range = typename range_proxy<T>::step_range_proxy;
17+
18+ template <typename T>
19+ __device__
20+ step_range<T> grid_stride_range (T begin, T end) {
21+ begin += blockDim .x * blockIdx .x + threadIdx .x ;
22+ return range (begin, end).step (gridDim .x * blockDim .x );
23+ }
24+ // ///////////////////////////////////////////////////////////////
25+
26+ template <typename T, typename Predicate>
27+ __device__
28+ void count_if (int *count, T *data, int n, Predicate p)
29+ {
30+ for (auto i : grid_stride_range (0 , n)) {
31+ if (p (data[i])) atomicAdd (count, 1 );
32+ }
33+ }
34+
35+ // Use count_if with a lambda function that searches for x, y, z or w
36+ // Note the use of range-based for loop and initializer_list inside the functor
37+ // We use auto so we don't have to know the type of the functor or array
38+ __global__
39+ void xyzw_frequency (int *count, char *text, int n)
40+ {
41+ const char letters[] { ' x' ,' y' ,' z' ,' w' };
42+
43+ count_if (count, text, n, [&](char c) {
44+ for (const auto x : letters)
45+ if (c == x) return true ;
46+ return false ;
47+ });
48+ }
49+
50+ __global__
51+ void xyzw_frequency_thrust_device (int *count, char *text, int n)
52+ {
53+ const char letters[] { ' x' ,' y' ,' z' ,' w' };
54+
55+ auto ptext = thrust::device_pointer_cast (text);
56+
57+ *count = thrust::count_if (thrust::device, ptext, ptext+n, [&](char c) {
58+ for (const auto x : letters)
59+ if (c == x) return true ;
60+ return false ;
61+ });
62+ }
63+
64+ // a bug in Thrust 1.8 causes warnings when this is uncommented
65+ // so commented out by default -- fixed in Thrust master branch
66+ #if 0
67+ void xyzw_frequency_thrust_host(int *count, char *text, int n)
68+ {
69+ const char letters[] { 'x','y','z','w' };
70+
71+ *count = thrust::count_if(thrust::host, text, text+n, [&](char c) {
72+ for (const auto x : letters)
73+ if (c == x) return true;
74+ return false;
75+ });
76+ }
77+ #endif
78+
79+ int main (int argc, char ** argv)
80+ {
81+ const char *filename = " warandpeace.txt" ;
82+
83+ int numBytes = 16 *1048576 ;
84+ char *h_text = (char *)malloc (numBytes);
85+
86+ char *d_text;
87+ cudaMalloc ((void **)&d_text, numBytes);
88+
89+ FILE *fp = fopen (filename, " r" );
90+ int len = fread (h_text, sizeof (char ), numBytes, fp);
91+ fclose (fp);
92+ std::cout << " Read " << len << " byte corpus from " << filename << std::endl;
93+
94+ cudaMemcpy (d_text, h_text, len, cudaMemcpyHostToDevice);
95+
96+ int count = 0 ;
97+ int *d_count;
98+ cudaMalloc (&d_count, sizeof (int ));
99+ cudaMemset (d_count, 0 , sizeof (int ));
100+
101+ // Try uncommenting one kernel call at a time
102+ xyzw_frequency<<<8 , 256 >>> (d_count, d_text, len);
103+ // xyzw_frequency_thrust_device<<<1, 1>>>(d_count, d_text, len);
104+ cudaMemcpy (&count, d_count, sizeof (int ), cudaMemcpyDeviceToHost);
105+
106+ // xyzw_frequency_thrust_host(&count, h_text, len);
107+
108+ std::cout << " counted " << count << " instances of 'x', 'y', 'z', or 'w' in \" "
109+ << filename << " \" " << std::endl;
110+
111+ cudaFree (d_count);
112+ cudaFree (d_text);
113+
114+ return 0 ;
115+ }
0 commit comments