mirror of
https://github.com/Steffo99/unimore-hpc-assignments.git
synced 2024-11-21 23:54:25 +00:00
HPC CUDA Lab 3
This commit is contained in:
parent
809d881f2f
commit
9570af5b66
26 changed files with 3823 additions and 4 deletions
12
README.md
12
README.md
|
@ -10,10 +10,14 @@ This repo contains the exercises and the tutorials used for Unimore's HPC class
|
|||
|
||||
### OpenMP Exercises
|
||||
The exercises related to OpenMP programming model can be found in the folder `openmp`. Here the list of currectly available classes:
|
||||
- `openmp\lab1`: OpenMP basics: *parallel*, *for-loop*, *sections*, and *tasking*.
|
||||
- `openmp\lab2`: OpenMP Advanced: *reduction*, *tasking*, *optimizations*.
|
||||
- `openmp\lab1`: OpenMP basics: *parallel*, *for-loop*, *sections*, and *tasking*
|
||||
- `openmp\lab2`: OpenMP Advanced: *reduction*, *tasking*, *optimizations*
|
||||
- `openmp\lab3`: OpenMP 4.x+: *Accelerator Model (targeting: Nvidia GP-GPU)*
|
||||
|
||||
### CUDA Exercises
|
||||
- `cuda\lab1`: CUDA Basics.
|
||||
- `cuda\lab2`: CUDA Memory Model.
|
||||
- `cuda\lab1`: CUDA Basics
|
||||
- `cuda\lab2`: CUDA Memory Model
|
||||
- `cuda\lab3`: CUDA Advanced Host Management
|
||||
|
||||
### (Optional)
|
||||
- `challenge`: Parallelize the code with everything you learned and submit the result before *21 May 2021*
|
||||
|
|
55
challenge/Makefile
Normal file
55
challenge/Makefile
Normal file
|
@ -0,0 +1,55 @@
|
|||
ifndef CUDA_HOME
|
||||
CUDA_HOME:=/usr/local/cuda
|
||||
endif
|
||||
|
||||
ifndef EXERCISE
|
||||
EXERCISE=TrackColour.cpp
|
||||
endif
|
||||
|
||||
BUILD_DIR ?= ./build
|
||||
|
||||
NVCC=$(CUDA_HOME)/bin/nvcc
|
||||
CXX=g++
|
||||
|
||||
OPT:=-O2 -g
|
||||
NVOPT:=-Xcompiler -fopenmp -lineinfo -arch=sm_53 --ptxas-options=-v --use_fast_math
|
||||
|
||||
CXXFLAGS:=$(OPT) -I. $(EXT_CXXFLAGS) `pkg-config --cflags --libs opencv4`
|
||||
LDFLAGS:=-lm -lcudart $(EXT_LDFLAGS)
|
||||
|
||||
NVCFLAGS:=$(CXXFLAGS) $(NVOPT)
|
||||
NVLDFLAGS:=$(LDFLAGS) -lgomp
|
||||
|
||||
SRCS:= utils.c
|
||||
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) $(EXERCISE:%=$(BUILD_DIR)/%.o)
|
||||
EXE=$(EXERCISE:%=%.exe)
|
||||
|
||||
$(EXE): $(OBJS)
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(NVCC) $(NVCFLAGS) $(OBJS) -o $@ $(NVLDFLAGS)
|
||||
|
||||
$(BUILD_DIR)/%.cu.o: %.cu
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(NVCC) $(NVCFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.cpp.o: %.cpp
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.c.o: %.c
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
all: $(EXE)
|
||||
|
||||
.PHONY: run profile clean
|
||||
run: $(EXE)
|
||||
./$(EXE)
|
||||
|
||||
profile: $(EXE)
|
||||
sudo LD_LIBRARY_PATH=$(CUDA_HOME)/lib:/usr/ext/lib:${LD_LIBRARY_PATH} LIBRARY_PATH=/usr/ext/lib:${LIBRARY_PATH} nvprof ./$(EXE)
|
||||
|
||||
clean:
|
||||
-rm -fr $(BUILD_DIR) *.exe *.out *~
|
||||
|
||||
MKDIR_P ?= mkdir -p
|
283
challenge/TrackColour.cpp
Normal file
283
challenge/TrackColour.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file colorTracking.cpp
|
||||
* @author Alessandro Capotondi
|
||||
* @date 5 May 2020
|
||||
* @brief Color Tracking
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "opencv2/imgproc/imgproc_c.h"
|
||||
#include "opencv2/imgproc/imgproc.hpp"
|
||||
#include <opencv2/imgcodecs/imgcodecs.hpp>
|
||||
#include <opencv2/objdetect/objdetect.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
#ifdef CHECK
|
||||
#include "data/sample_ground_truth.h"
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
void ConversionRgb2Hsv(uint8_t *__restrict__ out, uint8_t *__restrict__ in, int width, int height, int nch)
|
||||
{
|
||||
// Get Raw Image Data pointer
|
||||
int pixels = width * height * nch;
|
||||
|
||||
//Convert each pixel of input RGB image to HSV
|
||||
for (int idx = 0; idx < pixels; idx += nch)
|
||||
{
|
||||
uint8_t V, S, H;
|
||||
uint8_t rgb_min, rgb_max, rgb_mm;
|
||||
|
||||
//Read color channels
|
||||
uint8_t red = in[idx];
|
||||
uint8_t green = in[idx + 1];
|
||||
uint8_t blue = in[idx + 2];
|
||||
|
||||
rgb_max = max(max(red, green), blue);
|
||||
rgb_min = min(min(red, green), blue);
|
||||
rgb_mm = rgb_max - rgb_min;
|
||||
|
||||
//Value computation
|
||||
V = rgb_max;
|
||||
if (V == 0)
|
||||
H = S = 0;
|
||||
else
|
||||
{
|
||||
//Saturation computation
|
||||
S = (int)(((long)255 * (long)(rgb_mm)) / (long)V);
|
||||
if (S == 0)
|
||||
H = 0;
|
||||
else
|
||||
{
|
||||
//Hue computation
|
||||
if (rgb_max == red)
|
||||
H = 0 + 43 * (green - blue) / rgb_mm;
|
||||
else if (rgb_max == green)
|
||||
H = 85 + 43 * (blue - red) / rgb_mm;
|
||||
else
|
||||
H = 171 + 43 * (red - green) / rgb_mm;
|
||||
}
|
||||
}
|
||||
|
||||
//Write HSV
|
||||
out[idx] = (uint8_t)H;
|
||||
out[idx + 1] = (uint8_t)S;
|
||||
out[idx + 2] = (uint8_t)V;
|
||||
}
|
||||
}
|
||||
|
||||
void ImgThreashold(uint8_t *__restrict__ out, uint8_t *__restrict__ in, int32_t thLow[3], int32_t thHi[3], int width, int height, int nch)
|
||||
{
|
||||
int pixels = width * height;
|
||||
uint8_t lb1 = (uint8_t)thLow[0];
|
||||
uint8_t lb2 = (uint8_t)thLow[1];
|
||||
uint8_t lb3 = (uint8_t)thLow[2];
|
||||
uint8_t ub1 = (uint8_t)thHi[0];
|
||||
uint8_t ub2 = (uint8_t)thHi[1];
|
||||
uint8_t ub3 = (uint8_t)thHi[2];
|
||||
|
||||
for (int idx = 0; idx < pixels; ++idx)
|
||||
{
|
||||
out[idx] = ((in[idx * nch] >= lb1) && (in[idx * nch] <= ub1) &&
|
||||
(in[idx * nch + 1] >= lb2) && (in[idx * nch + 1] <= ub2) &&
|
||||
(in[idx * nch + 2] >= lb3) && (in[idx * nch + 2] <= ub3))
|
||||
? 255
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ImgCenterbyMoments(int *y, int *x, uint8_t *__restrict__ in, int width, int height, int nch)
|
||||
{
|
||||
uint64_t m_00 = 0, m_01 = 0, m_10 = 0;
|
||||
for (int i = 0; i < height; ++i)
|
||||
{
|
||||
for (int j = 0; j < width; ++j)
|
||||
{
|
||||
if (in[i * width + j] > 0)
|
||||
{
|
||||
m_00++;
|
||||
m_01 += j;
|
||||
m_10 += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
*y = m_00 ? (double)m_01 / m_00 : 0;
|
||||
*x = m_00 ? (double)m_10 / m_00 : 0;
|
||||
}
|
||||
|
||||
void ImgMerge(uint8_t *__restrict__ out, uint8_t *__restrict__ in1, uint8_t *__restrict__ in2, int width, int height, int nch)
|
||||
{
|
||||
// Get Raw Image Data pointer
|
||||
int pixels = width * height * nch;
|
||||
|
||||
for (int idx = 0; idx < pixels; ++idx)
|
||||
{
|
||||
if(in2[idx])
|
||||
out[idx] = in2[idx];
|
||||
else
|
||||
out[idx] = in1[idx];
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct timespec rt[2];
|
||||
double wt;
|
||||
|
||||
//Open Video Example
|
||||
VideoCapture cap("data/sample.avi");
|
||||
int width = cap.get(CAP_PROP_FRAME_WIDTH);
|
||||
int height = cap.get(CAP_PROP_FRAME_HEIGHT);
|
||||
int nCh = 3;
|
||||
|
||||
// Upper and Lower Color Threasholds
|
||||
int32_t thHi[3], thLow[3];
|
||||
Scalar _thHi, _thLow;
|
||||
|
||||
// Frame Buffers
|
||||
Mat frameRGB = Mat::zeros(height, width, CV_8UC3);
|
||||
Mat frameHVS = Mat::zeros(height, width, CV_8UC3);
|
||||
Mat frameTrack = Mat::zeros(height, width, CV_8UC3);
|
||||
Mat frameMask = Mat::zeros(height, width, CV_8UC1);
|
||||
|
||||
//Check Video
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cout << "[Error] Cannot open the video file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
if (argc == 7)
|
||||
{
|
||||
thLow[0] = atoi(argv[1]);
|
||||
thLow[1] = atoi(argv[2]);
|
||||
thLow[2] = atoi(argv[3]);
|
||||
thHi[0] = atoi(argv[4]);
|
||||
thHi[1] = atoi(argv[5]);
|
||||
thHi[2] = atoi(argv[6]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "[Error] Invalid arguments: usage ./cTracking [thLow(H S V) thHi(H S V)]" << endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Default Values
|
||||
thLow[0] = 160;
|
||||
thLow[1] = 100;
|
||||
thLow[2] = 100;
|
||||
thHi[0] = 180;
|
||||
thHi[1] = 255;
|
||||
thHi[2] = 255;
|
||||
}
|
||||
_thHi = Scalar(thHi[0], thHi[1], thHi[2]);
|
||||
|
||||
//Print Information
|
||||
printf("--------------------------------------\n");
|
||||
printf("Video Info\n");
|
||||
printf("--------------------------------------\n");
|
||||
printf("width :\t%d\n", (int)cap.get(CAP_PROP_FRAME_WIDTH));
|
||||
printf("height:\t%d\n", (int)cap.get(CAP_PROP_FRAME_HEIGHT));
|
||||
printf("fps :\t%d\n", (int)cap.get(CAP_PROP_FPS));
|
||||
printf("--------------------------------------\n");
|
||||
|
||||
int lastX = 0;
|
||||
int lastY = 0;
|
||||
int posX = 0;
|
||||
int posY = 0;
|
||||
#ifdef CHECK
|
||||
int check_id = 0;
|
||||
#endif
|
||||
int nFrames = 0;
|
||||
double time_cnt = 0.0;
|
||||
while (1)
|
||||
{
|
||||
bool lastFrame = cap.read(frameRGB); // read a new frame from video
|
||||
if (!lastFrame)
|
||||
break;
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
ConversionRgb2Hsv(frameHVS.ptr(), frameRGB.ptr(), width, height, nCh);
|
||||
ImgThreashold(frameMask.ptr(), frameHVS.ptr(), thLow, thHi, width, height, nCh);
|
||||
ImgCenterbyMoments(&posY, &posX, frameMask.ptr(), width, height, nCh);
|
||||
|
||||
// We want to draw a line only if its a valid position
|
||||
if (lastX > 0 && lastY > 0 && posX > 0 && posY > 0)
|
||||
line(frameTrack, Point(lastY, lastX), Point(posY, posX), _thHi, 2, CV_8UC3, 0);
|
||||
|
||||
ImgMerge(frameRGB.ptr(), frameRGB.ptr(), frameTrack.ptr(), width, height, nCh);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
time_cnt+= (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
nFrames++;
|
||||
|
||||
#ifdef DISPLAY
|
||||
// Show frames
|
||||
imshow("frameRGB", frameRGB);
|
||||
imshow("frameMask", frameMask);
|
||||
imshow("frameTrack", frameTrack);
|
||||
waitKey(1);
|
||||
#endif
|
||||
|
||||
#ifdef CHECK
|
||||
assert(ground_truth_YX[check_id++]==posY);
|
||||
assert(ground_truth_YX[check_id++]==posX);
|
||||
#endif
|
||||
lastX = posX;
|
||||
lastY = posY;
|
||||
}
|
||||
|
||||
printf("ColorTracking: %d frames, %9.6f s per-frame (%9.6f fps)\n", nFrames, time_cnt/nFrames, 1/(time_cnt/nFrames));
|
||||
|
||||
//Release Memory - Avoid Memory Leak!
|
||||
frameRGB.release();
|
||||
frameHVS.release();
|
||||
frameTrack.release();
|
||||
frameMask.release();
|
||||
cap.release();
|
||||
|
||||
return 0;
|
||||
}
|
BIN
challenge/data/sample.avi
Normal file
BIN
challenge/data/sample.avi
Normal file
Binary file not shown.
595
challenge/data/sample_ground_truth.h
Normal file
595
challenge/data/sample_ground_truth.h
Normal file
|
@ -0,0 +1,595 @@
|
|||
short ground_truth_YX[] = {
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 522,
|
||||
950, 521,
|
||||
950, 521,
|
||||
950, 521,
|
||||
951, 520,
|
||||
951, 520,
|
||||
951, 520,
|
||||
950, 520,
|
||||
949, 520,
|
||||
949, 520,
|
||||
949, 520,
|
||||
949, 520,
|
||||
949, 519,
|
||||
949, 519,
|
||||
949, 519,
|
||||
950, 518,
|
||||
949, 518,
|
||||
949, 518,
|
||||
949, 518,
|
||||
949, 518,
|
||||
948, 518,
|
||||
948, 518,
|
||||
948, 518,
|
||||
947, 518,
|
||||
946, 517,
|
||||
946, 517,
|
||||
946, 517,
|
||||
945, 516,
|
||||
945, 516,
|
||||
945, 516,
|
||||
944, 514,
|
||||
944, 512,
|
||||
944, 512,
|
||||
943, 508,
|
||||
943, 503,
|
||||
944, 497,
|
||||
945, 491,
|
||||
945, 491,
|
||||
943, 484,
|
||||
942, 478,
|
||||
942, 478,
|
||||
940, 472,
|
||||
938, 466,
|
||||
933, 460,
|
||||
933, 460,
|
||||
928, 454,
|
||||
923, 447,
|
||||
919, 440,
|
||||
919, 440,
|
||||
914, 434,
|
||||
909, 426,
|
||||
905, 419,
|
||||
905, 419,
|
||||
903, 410,
|
||||
903, 400,
|
||||
903, 400,
|
||||
901, 391,
|
||||
899, 380,
|
||||
895, 369,
|
||||
890, 358,
|
||||
890, 358,
|
||||
884, 348,
|
||||
878, 338,
|
||||
878, 338,
|
||||
871, 328,
|
||||
861, 318,
|
||||
861, 318,
|
||||
850, 308,
|
||||
839, 299,
|
||||
829, 291,
|
||||
820, 284,
|
||||
820, 284,
|
||||
811, 277,
|
||||
804, 273,
|
||||
804, 273,
|
||||
799, 271,
|
||||
796, 268,
|
||||
794, 265,
|
||||
794, 265,
|
||||
793, 265,
|
||||
790, 265,
|
||||
790, 265,
|
||||
789, 263,
|
||||
790, 264,
|
||||
791, 263,
|
||||
793, 264,
|
||||
793, 264,
|
||||
796, 263,
|
||||
802, 264,
|
||||
802, 264,
|
||||
808, 261,
|
||||
816, 257,
|
||||
816, 257,
|
||||
826, 256,
|
||||
837, 254,
|
||||
847, 251,
|
||||
857, 251,
|
||||
857, 251,
|
||||
865, 250,
|
||||
873, 250,
|
||||
873, 250,
|
||||
880, 250,
|
||||
888, 249,
|
||||
897, 248,
|
||||
897, 248,
|
||||
905, 248,
|
||||
912, 250,
|
||||
918, 249,
|
||||
918, 249,
|
||||
923, 252,
|
||||
927, 252,
|
||||
928, 253,
|
||||
928, 253,
|
||||
927, 252,
|
||||
924, 251,
|
||||
924, 251,
|
||||
920, 251,
|
||||
915, 251,
|
||||
907, 251,
|
||||
898, 250,
|
||||
898, 250,
|
||||
888, 250,
|
||||
876, 251,
|
||||
876, 251,
|
||||
860, 254,
|
||||
843, 256,
|
||||
843, 256,
|
||||
826, 259,
|
||||
809, 262,
|
||||
792, 265,
|
||||
779, 269,
|
||||
779, 269,
|
||||
767, 270,
|
||||
755, 271,
|
||||
755, 271,
|
||||
744, 273,
|
||||
732, 276,
|
||||
721, 277,
|
||||
721, 277,
|
||||
713, 278,
|
||||
704, 279,
|
||||
704, 279,
|
||||
697, 279,
|
||||
690, 279,
|
||||
685, 280,
|
||||
679, 281,
|
||||
679, 281,
|
||||
674, 283,
|
||||
666, 284,
|
||||
666, 284,
|
||||
660, 288,
|
||||
652, 294,
|
||||
652, 294,
|
||||
644, 299,
|
||||
635, 304,
|
||||
626, 309,
|
||||
617, 312,
|
||||
617, 312,
|
||||
605, 315,
|
||||
593, 319,
|
||||
593, 319,
|
||||
578, 323,
|
||||
562, 329,
|
||||
548, 335,
|
||||
548, 335,
|
||||
535, 343,
|
||||
523, 350,
|
||||
512, 359,
|
||||
512, 359,
|
||||
499, 367,
|
||||
486, 374,
|
||||
475, 381,
|
||||
475, 381,
|
||||
462, 387,
|
||||
448, 393,
|
||||
448, 393,
|
||||
433, 398,
|
||||
421, 403,
|
||||
409, 407,
|
||||
401, 411,
|
||||
401, 411,
|
||||
394, 415,
|
||||
391, 417,
|
||||
391, 417,
|
||||
387, 420,
|
||||
382, 423,
|
||||
375, 427,
|
||||
375, 427,
|
||||
371, 431,
|
||||
366, 436,
|
||||
359, 440,
|
||||
359, 440,
|
||||
353, 443,
|
||||
347, 447,
|
||||
347, 447,
|
||||
340, 450,
|
||||
336, 453,
|
||||
331, 457,
|
||||
331, 457,
|
||||
324, 460,
|
||||
318, 464,
|
||||
318, 464,
|
||||
318, 464,
|
||||
313, 469,
|
||||
309, 472,
|
||||
306, 475,
|
||||
303, 477,
|
||||
300, 481,
|
||||
299, 484,
|
||||
299, 484,
|
||||
304, 489,
|
||||
314, 495,
|
||||
323, 502,
|
||||
323, 502,
|
||||
334, 511,
|
||||
348, 519,
|
||||
366, 526,
|
||||
366, 526,
|
||||
387, 532,
|
||||
409, 536,
|
||||
433, 538,
|
||||
433, 538,
|
||||
457, 539,
|
||||
482, 538,
|
||||
482, 538,
|
||||
508, 536,
|
||||
536, 532,
|
||||
565, 527,
|
||||
565, 527,
|
||||
591, 522,
|
||||
616, 518,
|
||||
637, 516,
|
||||
637, 516,
|
||||
655, 514,
|
||||
673, 513,
|
||||
673, 513,
|
||||
689, 514,
|
||||
706, 515,
|
||||
720, 516,
|
||||
733, 517,
|
||||
733, 517,
|
||||
746, 519,
|
||||
759, 521,
|
||||
759, 521,
|
||||
771, 522,
|
||||
782, 524,
|
||||
792, 527,
|
||||
792, 527,
|
||||
802, 530,
|
||||
811, 533,
|
||||
820, 536,
|
||||
820, 536,
|
||||
830, 538,
|
||||
841, 540,
|
||||
853, 543,
|
||||
853, 543,
|
||||
867, 546,
|
||||
880, 548,
|
||||
880, 548,
|
||||
892, 550,
|
||||
905, 551,
|
||||
919, 551,
|
||||
932, 552,
|
||||
932, 552,
|
||||
945, 552,
|
||||
956, 552,
|
||||
956, 552,
|
||||
967, 550,
|
||||
978, 550,
|
||||
978, 550,
|
||||
989, 550,
|
||||
998, 550,
|
||||
1004, 551,
|
||||
1004, 551,
|
||||
1009, 551,
|
||||
1015, 552,
|
||||
1018, 553,
|
||||
1018, 553,
|
||||
1017, 552,
|
||||
1015, 550,
|
||||
1012, 547,
|
||||
1012, 547,
|
||||
1010, 542,
|
||||
1008, 537,
|
||||
1008, 537,
|
||||
1007, 532,
|
||||
1007, 526,
|
||||
1005, 520,
|
||||
1003, 512,
|
||||
1003, 512,
|
||||
1002, 504,
|
||||
999, 494,
|
||||
999, 494,
|
||||
998, 483,
|
||||
993, 472,
|
||||
993, 472,
|
||||
985, 460,
|
||||
978, 447,
|
||||
970, 435,
|
||||
962, 423,
|
||||
962, 423,
|
||||
953, 410,
|
||||
940, 397,
|
||||
940, 397,
|
||||
929, 384,
|
||||
918, 371,
|
||||
908, 358,
|
||||
908, 358,
|
||||
901, 346,
|
||||
893, 334,
|
||||
885, 321,
|
||||
885, 321,
|
||||
877, 309,
|
||||
865, 296,
|
||||
852, 284,
|
||||
852, 284,
|
||||
837, 272,
|
||||
823, 261,
|
||||
823, 261,
|
||||
813, 253,
|
||||
803, 246,
|
||||
803, 246,
|
||||
793, 241,
|
||||
787, 238,
|
||||
782, 234,
|
||||
777, 229,
|
||||
777, 229,
|
||||
774, 227,
|
||||
769, 226,
|
||||
769, 226,
|
||||
765, 227,
|
||||
762, 227,
|
||||
760, 225,
|
||||
760, 225,
|
||||
759, 227,
|
||||
759, 226,
|
||||
761, 225,
|
||||
761, 225,
|
||||
762, 225,
|
||||
762, 226,
|
||||
760, 226,
|
||||
760, 226,
|
||||
756, 224,
|
||||
748, 225,
|
||||
748, 225,
|
||||
739, 227,
|
||||
727, 226,
|
||||
713, 228,
|
||||
701, 232,
|
||||
701, 232,
|
||||
688, 235,
|
||||
674, 241,
|
||||
674, 241,
|
||||
663, 244,
|
||||
655, 246,
|
||||
655, 246,
|
||||
646, 248,
|
||||
637, 252,
|
||||
629, 253,
|
||||
620, 256,
|
||||
620, 256,
|
||||
612, 257,
|
||||
604, 259,
|
||||
604, 259,
|
||||
594, 260,
|
||||
583, 263,
|
||||
573, 264,
|
||||
573, 264,
|
||||
562, 265,
|
||||
550, 267,
|
||||
538, 267,
|
||||
538, 267,
|
||||
526, 268,
|
||||
515, 269,
|
||||
504, 269,
|
||||
504, 269,
|
||||
495, 271,
|
||||
487, 272,
|
||||
487, 272,
|
||||
477, 272,
|
||||
466, 273,
|
||||
466, 273,
|
||||
455, 275,
|
||||
444, 277,
|
||||
433, 279,
|
||||
423, 283,
|
||||
423, 283,
|
||||
414, 287,
|
||||
405, 291,
|
||||
405, 291,
|
||||
402, 296,
|
||||
402, 300,
|
||||
406, 305,
|
||||
406, 305,
|
||||
411, 311,
|
||||
420, 318,
|
||||
430, 329,
|
||||
430, 329,
|
||||
439, 340,
|
||||
449, 354,
|
||||
457, 367,
|
||||
457, 367,
|
||||
462, 380,
|
||||
466, 396,
|
||||
466, 396,
|
||||
469, 411,
|
||||
470, 428,
|
||||
472, 444,
|
||||
473, 459,
|
||||
473, 459,
|
||||
476, 473,
|
||||
479, 485,
|
||||
479, 485,
|
||||
484, 496,
|
||||
491, 508,
|
||||
499, 518,
|
||||
499, 518,
|
||||
507, 527,
|
||||
515, 536,
|
||||
520, 545,
|
||||
520, 545,
|
||||
525, 551,
|
||||
529, 555,
|
||||
529, 555,
|
||||
531, 558,
|
||||
534, 559,
|
||||
536, 559,
|
||||
536, 559,
|
||||
538, 559,
|
||||
541, 559,
|
||||
546, 558,
|
||||
546, 558,
|
||||
553, 556,
|
||||
560, 554,
|
||||
568, 553,
|
||||
568, 553,
|
||||
577, 551,
|
||||
586, 550,
|
||||
586, 550,
|
||||
598, 549,
|
||||
611, 547,
|
||||
626, 546,
|
||||
642, 545,
|
||||
642, 545,
|
||||
657, 544,
|
||||
672, 542,
|
||||
672, 542,
|
||||
689, 542,
|
||||
709, 541,
|
||||
728, 540,
|
||||
728, 540,
|
||||
745, 537,
|
||||
761, 535,
|
||||
779, 535,
|
||||
779, 535,
|
||||
798, 536,
|
||||
814, 538,
|
||||
829, 539,
|
||||
829, 539,
|
||||
844, 541,
|
||||
859, 542,
|
||||
859, 542,
|
||||
873, 542,
|
||||
888, 543,
|
||||
888, 543,
|
||||
905, 544,
|
||||
918, 544,
|
||||
931, 545,
|
||||
943, 546,
|
||||
943, 546,
|
||||
954, 545,
|
||||
960, 542,
|
||||
960, 542,
|
||||
959, 538,
|
||||
956, 535,
|
||||
953, 532,
|
||||
953, 532,
|
||||
949, 530,
|
||||
947, 528,
|
||||
946, 526,
|
||||
946, 526,
|
||||
944, 522,
|
||||
944, 517,
|
||||
943, 511,
|
||||
943, 511,
|
||||
943, 502,
|
||||
941, 493,
|
||||
941, 493,
|
||||
937, 482,
|
||||
934, 470,
|
||||
931, 458,
|
||||
926, 445,
|
||||
926, 445,
|
||||
921, 432,
|
||||
913, 420,
|
||||
913, 420,
|
||||
903, 408,
|
||||
893, 396,
|
||||
893, 396,
|
||||
884, 386,
|
||||
872, 376,
|
||||
860, 367,
|
||||
848, 358,
|
||||
848, 358,
|
||||
839, 349,
|
||||
831, 341,
|
||||
831, 341,
|
||||
823, 333,
|
||||
814, 326,
|
||||
807, 321,
|
||||
807, 321,
|
||||
801, 317,
|
||||
796, 315,
|
||||
796, 315,
|
||||
791, 313,
|
||||
789, 315,
|
||||
790, 315,
|
||||
792, 316,
|
||||
792, 316,
|
||||
795, 317,
|
||||
798, 317,
|
||||
798, 317,
|
||||
799, 318,
|
||||
803, 317,
|
||||
803, 317,
|
||||
806, 315,
|
||||
809, 315,
|
||||
814, 314,
|
||||
819, 314,
|
||||
819, 314,
|
||||
825, 313,
|
||||
830, 313,
|
||||
830, 313,
|
||||
832, 313,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 312,
|
||||
834, 314,
|
||||
836, 314,
|
||||
838, 314,
|
||||
838, 314,
|
||||
838, 317,
|
||||
836, 320,
|
||||
836, 320,
|
||||
835, 321,
|
||||
834, 323,
|
||||
832, 325,
|
||||
832, 327,
|
||||
832, 327,
|
||||
834, 329,
|
||||
836, 331,
|
||||
836, 331,
|
||||
839, 332,
|
||||
843, 334,
|
||||
843, 334,
|
||||
846, 335,
|
||||
849, 335,
|
||||
852, 338,
|
||||
854, 339,
|
||||
854, 339,
|
||||
855, 340,
|
||||
855, 341,
|
||||
855, 341,
|
||||
855, 342,
|
||||
854, 343,
|
||||
855, 342,
|
||||
855, 342,
|
||||
854, 344,
|
||||
852, 345,
|
||||
852, 345,
|
||||
850, 346,
|
||||
849, 347};
|
138
challenge/utils.c
Normal file
138
challenge/utils.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* @file utils.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 27 Mar 2020
|
||||
* @brief File containing utilities functions for HPC Unimore Class
|
||||
*
|
||||
* Utilities for OpenMP lab.
|
||||
*
|
||||
* @see http://algo.ing.unimo.it/people/andrea/Didattica/HPC/index.html
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_ITERATIONS 100
|
||||
static struct timespec timestampA, timestampB;
|
||||
static unsigned long long statistics[MAX_ITERATIONS];
|
||||
static int iterations = 0;
|
||||
|
||||
static unsigned long long __diff_ns(struct timespec start, struct timespec end)
|
||||
{
|
||||
struct timespec temp;
|
||||
if ((end.tv_nsec - start.tv_nsec) < 0)
|
||||
{
|
||||
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
|
||||
temp.tv_nsec = 1000000000ULL + end.tv_nsec - start.tv_nsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.tv_sec = end.tv_sec - start.tv_sec;
|
||||
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
|
||||
}
|
||||
|
||||
return temp.tv_nsec + temp.tv_sec * 1000000000ULL;
|
||||
}
|
||||
|
||||
void start_timer()
|
||||
{
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, ×tampA);
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void stop_timer()
|
||||
{
|
||||
unsigned long long elapsed = 0ULL;
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, ×tampB);
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
unsigned long long elapsed_ns()
|
||||
{
|
||||
return __diff_ns(timestampA, timestampB);
|
||||
}
|
||||
|
||||
void start_stats()
|
||||
{
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void collect_stats()
|
||||
{
|
||||
assert(iterations < MAX_ITERATIONS);
|
||||
stop_timer();
|
||||
statistics[iterations++] = elapsed_ns();
|
||||
}
|
||||
|
||||
void print_stats()
|
||||
{
|
||||
unsigned long long min = ULLONG_MAX;
|
||||
unsigned long long max = 0LL;
|
||||
double average = 0.0;
|
||||
double std_deviation = 0.0;
|
||||
double sum = 0.0;
|
||||
|
||||
/* Compute the sum of all elements */
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
if (statistics[i] > max)
|
||||
max = statistics[i];
|
||||
if (statistics[i] < min)
|
||||
min = statistics[i];
|
||||
sum = sum + statistics[i] / 1E6;
|
||||
}
|
||||
average = sum / (double)iterations;
|
||||
|
||||
/* Compute variance and standard deviation */
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
sum = sum + pow((statistics[i] / 1E6 - average), 2);
|
||||
}
|
||||
std_deviation = sqrt(sum / (double)iterations);
|
||||
|
||||
printf("AvgTime\tMinTime\tMaxTime\tStdDev\n");
|
||||
printf("%.4f ms\t%.4f ms\t%.4f ms\t%.4f\n", (double)average, (double)min / 1E6, (double)max / 1E6, (double)std_deviation);
|
||||
}
|
||||
|
||||
}
|
142
challenge/utils.h
Normal file
142
challenge/utils.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file utils.h
|
||||
* @author Alessandro Capotondi
|
||||
* @date 27 Mar 2020
|
||||
* @brief File containing utilities functions for HPC Unimore Class
|
||||
*
|
||||
* The header define time functions and dummy workload used on the example tests.
|
||||
*
|
||||
* @see http://algo.ing.unimo.it/people/andrea/Didattica/HPC/index.html
|
||||
*/
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(VERBOSE)
|
||||
#define DEBUG_PRINT(x, ...) printf((x), ##__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINT(x, ...)
|
||||
#endif
|
||||
|
||||
#if !defined(NTHREADS)
|
||||
#define NTHREADS (4)
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The function set the timestampA
|
||||
*
|
||||
* The function is used to measure elapsed time between two execution points.
|
||||
* The function start_timer() sets the starting point timestamp, while the function
|
||||
* stop_timer() sets the termination timestamp. The elapsed time, expressed in nanoseconds,
|
||||
* between the two points can be retrieved using the function elapsed_ns().
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* start_timer(); // Point A
|
||||
* //SOME CODE HERE
|
||||
* stop_timer(); // Point B
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and B
|
||||
* //SOME OTHER CODE HERE
|
||||
* stop_timer(); // Point C
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and C
|
||||
* @endcode
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
* @see elapsed_ns()
|
||||
*/
|
||||
void start_timer();
|
||||
|
||||
/**
|
||||
* @brief The function set the second timestamps
|
||||
*
|
||||
* The function is used to measure elapsed time between two execution points.
|
||||
* The function start_timer() sets the starting point timestamp, while the function
|
||||
* stop_timer() returns the elapsed time, expressed in nanoseconds between the last call
|
||||
* of start_timer() and the current execution point.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* start_timer(); // Point A
|
||||
* //SOME CODE HERE
|
||||
* stop_timer(); // Point B
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and B
|
||||
* //SOME OTHER CODE HERE
|
||||
* stop_timer(); // Point C
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and C
|
||||
* @endcode
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
* @see elapsed_ns()
|
||||
*/
|
||||
void stop_timer();
|
||||
|
||||
/**
|
||||
* @brief Elapsed nano seconds between start_timer() and stop_timer().
|
||||
*
|
||||
* @return Elapsed nano seconds
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
*/
|
||||
unsigned long long elapsed_ns();
|
||||
|
||||
/**
|
||||
* @brief The function init the starting point of stat measurement.
|
||||
*
|
||||
* The function is similar to start_timer().
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer
|
||||
*/
|
||||
void start_stats();
|
||||
|
||||
/**
|
||||
* @brief The function collects the elapsed time between the current exeuction point and the
|
||||
* last call of start_stats().
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void collect_stats();
|
||||
|
||||
/**
|
||||
* @brief The function display the collected statistics.
|
||||
* @return void
|
||||
*/
|
||||
void print_stats();
|
||||
}
|
||||
#endif /*__UTILS_H__*/
|
232
cuda/lab3/.solutions/gemm-v1.cu
Normal file
232
cuda/lab3/.solutions/gemm-v1.cu
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file gemm.cu
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief GEMM Kernel
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
|
||||
#ifndef N
|
||||
#define N (1 << 10)
|
||||
#endif
|
||||
#ifndef TILE_W
|
||||
#define TILE_W 128
|
||||
#endif
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE 32
|
||||
#endif
|
||||
|
||||
#define SM 64
|
||||
static void reorder(float *__restrict__ a, float *__restrict__ b, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
for (int j = 0; j < SM; j++)
|
||||
b[i * SM + j] = a[i * n + j];
|
||||
}
|
||||
|
||||
static void mm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
{
|
||||
for (int k = 0; k < SM; k++)
|
||||
{
|
||||
for (int j = 0; j < SM; j++)
|
||||
{
|
||||
c[i * n + j] += a[i * n + k] * b[k * SM + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void gemm_host(float *a, float *b, float *c, int n)
|
||||
{
|
||||
int bk = n / SM;
|
||||
#pragma omp parallel for collapse(3)
|
||||
for (int i = 0; i < bk; i++)
|
||||
{
|
||||
for (int j = 0; j < bk; j++)
|
||||
{
|
||||
for (int k = 0; k < bk; k++)
|
||||
{
|
||||
float b2[SM * SM];
|
||||
reorder(&b[SM * (k * n + j)], b2, n);
|
||||
mm(&a[SM * (i * n + k)], b2, &c[SM * (i * n + j)], n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
__global__ void gemm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
|
||||
__shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
|
||||
|
||||
int ib = blockIdx.y;
|
||||
int jb = blockIdx.x;
|
||||
|
||||
int it = threadIdx.y;
|
||||
int jt = threadIdx.x;
|
||||
|
||||
int a_offset, b_offset, c_offset;
|
||||
|
||||
float Cvalue = 0.0f;
|
||||
for (int kb = 0; kb < (n / BLOCK_SIZE); ++kb)
|
||||
{
|
||||
a_offset = ib * n * BLOCK_SIZE + kb * BLOCK_SIZE;
|
||||
b_offset = kb * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
As[it][jt] = a[a_offset + it * n + jt];
|
||||
Bs[it][jt] = b[b_offset + it * n + jt];
|
||||
__syncthreads();
|
||||
|
||||
for (int k = 0; k < BLOCK_SIZE; ++k)
|
||||
Cvalue += As[it][k] * Bs[k][jt];
|
||||
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
c_offset = ib * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
c[c_offset + it * n + jt] = Cvalue;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n = N, iret = 0;
|
||||
float *a, *b, *c, *g;
|
||||
struct timespec rt[2];
|
||||
double wt; // walltime
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocManaged
|
||||
gpuErrchk(cudaMallocHost((void **)&a, sizeof(float) * n *n));
|
||||
gpuErrchk(cudaMallocHost((void **)&b, sizeof(float) * n *n));
|
||||
gpuErrchk(cudaMallocHost((void **)&c, sizeof(float) * n *n));
|
||||
if (NULL == (g = (float *)malloc(sizeof(*g) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
|
||||
if (0 != iret)
|
||||
{
|
||||
gpuErrchk(cudaFreeHost(a));
|
||||
gpuErrchk(cudaFreeHost(b));
|
||||
gpuErrchk(cudaFreeHost(c));
|
||||
free(g);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
int _b = rand() % TWO04;
|
||||
int _c = rand() % TWO08;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
a[i] = _b / (float)TWO02;
|
||||
b[i] = _c / (float)TWO04;
|
||||
c[i] = g[i] = 0.0;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
gemm_host(a, b, g, n);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM (Host) : %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
//TODO Remove if unecessary
|
||||
float *d_a, *d_b, *d_c;
|
||||
gpuErrchk(cudaMalloc((void **)&d_a, sizeof(float) * n * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_b, sizeof(float) * n * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_c, sizeof(float) * n * n));
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(d_a, a, sizeof(float) * n * n, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpy(d_b, b, sizeof(float) * n * n, cudaMemcpyHostToDevice));
|
||||
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
|
||||
dim3 dimGrid((n + (BLOCK_SIZE)-1) / (BLOCK_SIZE), (n + (BLOCK_SIZE)-1) / (BLOCK_SIZE));
|
||||
gemm<<<dimGrid, dimBlock>>>(d_a, d_b, d_c, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(c, d_c, sizeof(float) * n * n, cudaMemcpyDeviceToHost));
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM-v1 (GPU): %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
iret = *(int *)(g + i) ^ *(int *)(c + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFreeHost(a));
|
||||
gpuErrchk(cudaFreeHost(b));
|
||||
gpuErrchk(cudaFreeHost(c));
|
||||
free(g);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_a));
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_b));
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_c));
|
||||
|
||||
return 0;
|
||||
}
|
214
cuda/lab3/.solutions/gemm-v2.cu
Normal file
214
cuda/lab3/.solutions/gemm-v2.cu
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file gemm.cu
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief GEMM Kernel
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
|
||||
#ifndef N
|
||||
#define N (1 << 10)
|
||||
#endif
|
||||
#ifndef TILE_W
|
||||
#define TILE_W 128
|
||||
#endif
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE 32
|
||||
#endif
|
||||
|
||||
#define SM 64
|
||||
static void reorder(float *__restrict__ a, float *__restrict__ b, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
for (int j = 0; j < SM; j++)
|
||||
b[i * SM + j] = a[i * n + j];
|
||||
}
|
||||
|
||||
static void mm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
{
|
||||
for (int k = 0; k < SM; k++)
|
||||
{
|
||||
for (int j = 0; j < SM; j++)
|
||||
{
|
||||
c[i * n + j] += a[i * n + k] * b[k * SM + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void gemm_host(float *a, float *b, float *c, int n)
|
||||
{
|
||||
int bk = n / SM;
|
||||
#pragma omp parallel for collapse(3)
|
||||
for (int i = 0; i < bk; i++)
|
||||
{
|
||||
for (int j = 0; j < bk; j++)
|
||||
{
|
||||
for (int k = 0; k < bk; k++)
|
||||
{
|
||||
float b2[SM * SM];
|
||||
reorder(&b[SM * (k * n + j)], b2, n);
|
||||
mm(&a[SM * (i * n + k)], b2, &c[SM * (i * n + j)], n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
__global__ void gemm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
|
||||
__shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
|
||||
|
||||
int ib = blockIdx.y;
|
||||
int jb = blockIdx.x;
|
||||
|
||||
int it = threadIdx.y;
|
||||
int jt = threadIdx.x;
|
||||
|
||||
int a_offset, b_offset, c_offset;
|
||||
|
||||
float Cvalue = 0.0f;
|
||||
for (int kb = 0; kb < (n / BLOCK_SIZE); ++kb)
|
||||
{
|
||||
a_offset = ib * n * BLOCK_SIZE + kb * BLOCK_SIZE;
|
||||
b_offset = kb * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
As[it][jt] = a[a_offset + it * n + jt];
|
||||
Bs[it][jt] = b[b_offset + it * n + jt];
|
||||
__syncthreads();
|
||||
|
||||
for (int k = 0; k < BLOCK_SIZE; ++k)
|
||||
Cvalue += As[it][k] * Bs[k][jt];
|
||||
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
c_offset = ib * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
c[c_offset + it * n + jt] = Cvalue;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n = N, iret = 0;
|
||||
float *a, *b, *c, *g;
|
||||
struct timespec rt[2];
|
||||
double wt; // walltime
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocManaged
|
||||
gpuErrchk(cudaMallocManaged((void **)&a, sizeof(float) * n *n));
|
||||
gpuErrchk(cudaMallocManaged((void **)&b, sizeof(float) * n *n));
|
||||
gpuErrchk(cudaMallocManaged((void **)&c, sizeof(float) * n *n));
|
||||
if (NULL == (g = (float *)malloc(sizeof(*g) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
|
||||
if (0 != iret)
|
||||
{
|
||||
gpuErrchk(cudaFree(a));
|
||||
gpuErrchk(cudaFree(b));
|
||||
gpuErrchk(cudaFree(c));
|
||||
free(g);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
int _b = rand() % TWO04;
|
||||
int _c = rand() % TWO08;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
a[i] = _b / (float)TWO02;
|
||||
b[i] = _c / (float)TWO04;
|
||||
c[i] = g[i] = 0.0;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
gemm_host(a, b, g, n);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM (Host) : %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
|
||||
dim3 dimGrid((n + (BLOCK_SIZE)-1) / (BLOCK_SIZE), (n + (BLOCK_SIZE)-1) / (BLOCK_SIZE));
|
||||
gemm<<<dimGrid, dimBlock>>>(a, b, c, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
cudaDeviceSynchronize();
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM-v1 (GPU): %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
iret = *(int *)(g + i) ^ *(int *)(c + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
gpuErrchk(cudaFree(a));
|
||||
gpuErrchk(cudaFree(b));
|
||||
gpuErrchk(cudaFree(c));
|
||||
free(g);
|
||||
return 0;
|
||||
}
|
175
cuda/lab3/.solutions/saxpy-v1.cu
Normal file
175
cuda/lab3/.solutions/saxpy-v1.cu
Normal file
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (512)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float *__restrict__ y, float a, float *__restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd \
|
||||
: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float *__restrict__ y, float a, float *__restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x, *d_x;
|
||||
float *h_y, *d_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
gpuErrchk(cudaMallocHost((void **)&h_x, sizeof(float) * n));
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
gpuErrchk(cudaMallocHost((void **)&h_y, sizeof(float) * n));
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
cudaFreeHost(h_x);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
cudaFreeHost(h_y);
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMalloc((void **)&d_x, sizeof(float) * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_y, sizeof(float) * n));
|
||||
|
||||
start_timer();
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(d_x, h_x, sizeof(float) * n, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpy(d_y, h_y, sizeof(float) * n, cudaMemcpyHostToDevice));
|
||||
gpu_saxpy<<<((n + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE>>>(d_y, a, d_x, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(h_y, d_y, sizeof(float) * n, cudaMemcpyDeviceToHost));
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float)elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float)elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFreeHost((void *)h_x));
|
||||
gpuErrchk(cudaFree(d_x));
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFreeHost((void *)h_y));
|
||||
gpuErrchk(cudaFree(d_y));
|
||||
free(h_z);
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
167
cuda/lab3/.solutions/saxpy-v2.cu
Normal file
167
cuda/lab3/.solutions/saxpy-v2.cu
Normal file
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (512)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x;
|
||||
float *h_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
gpuErrchk(cudaMallocManaged((void **)&h_x, sizeof(float) * n));
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
gpuErrchk(cudaMallocManaged((void **)&h_y, sizeof(float) * n));
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFree(h_x));
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFree(h_y));
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
//TODO Remove if unecessary
|
||||
|
||||
start_timer();
|
||||
//TODO Remove if unecessary
|
||||
gpu_saxpy<<<((n + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE>>>(h_y, a, h_x, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
//TODO Remove if unecessary
|
||||
cudaDeviceSynchronize();
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
gpuErrchk(cudaFree(h_x));
|
||||
gpuErrchk(cudaFree(h_y));
|
||||
free(h_z);
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
197
cuda/lab3/.solutions/saxpy-v3.cu
Normal file
197
cuda/lab3/.solutions/saxpy-v3.cu
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (512)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x, *d_x;
|
||||
float *h_y, *d_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
if (NULL == (h_x = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'x'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (h_y = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'y'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
free(h_x);
|
||||
free(h_y);
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
//CUDA Buffer Allocation
|
||||
gpuErrchk(cudaMalloc((void **)&d_x, sizeof(float) * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_y, sizeof(float) * n));
|
||||
|
||||
start_timer();
|
||||
int TILE = n / 8;
|
||||
//TODO Copy the first Tile (i=0)
|
||||
gpuErrchk(cudaMemcpyAsync(&d_x[0], &h_x[0], sizeof(float) * TILE, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpyAsync(&d_y[0], &h_y[0], sizeof(float) * TILE, cudaMemcpyHostToDevice));
|
||||
//TODO Loop over the Tiles
|
||||
for (int i = 0; i < n; i += TILE)
|
||||
{
|
||||
//TODO Wait Tile i
|
||||
cudaDeviceSynchronize();
|
||||
|
||||
//TODO Copy the out tile i-1
|
||||
if(i>0)
|
||||
gpuErrchk(cudaMemcpyAsync(&h_y[i-TILE], &d_y[i-TILE], sizeof(float) * TILE, cudaMemcpyDeviceToHost));
|
||||
|
||||
//TODO Launch Kernel over tile i
|
||||
gpu_saxpy<<<((TILE + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE>>>(&d_y[i], a, &d_x[i], TILE);
|
||||
|
||||
//TODO Copy the in tile i+=TILE
|
||||
if(i+TILE < n){
|
||||
gpuErrchk(cudaMemcpyAsync(&d_x[i+TILE], &h_x[i+TILE], sizeof(float) * TILE, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpyAsync(&d_y[i+TILE], &h_y[i+TILE], sizeof(float) * TILE, cudaMemcpyHostToDevice));
|
||||
}
|
||||
}
|
||||
//TODO Copy out the last tile n-TILE
|
||||
gpuErrchk(cudaMemcpyAsync(&h_y[n-TILE], &d_y[n-TILE], sizeof(float) * TILE, cudaMemcpyDeviceToHost));
|
||||
//TODO Wait last tile
|
||||
cudaDeviceSynchronize();
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//CUDA Buffer Allocation
|
||||
free(h_x);
|
||||
gpuErrchk(cudaFree(d_x));
|
||||
free(h_y);
|
||||
gpuErrchk(cudaFree(d_y));
|
||||
free(h_z);
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
197
cuda/lab3/.solutions/saxpy-v4.cu
Normal file
197
cuda/lab3/.solutions/saxpy-v4.cu
Normal file
|
@ -0,0 +1,197 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (512)
|
||||
#endif
|
||||
|
||||
#ifndef N_STREAMS
|
||||
#define N_STREAMS (16)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x, *d_x;
|
||||
float *h_y, *d_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
if (NULL == (h_x = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'x'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (h_y = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'y'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
free(h_x);
|
||||
free(h_y);
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
//CUDA Buffer Allocation
|
||||
gpuErrchk(cudaMalloc((void **)&d_x, sizeof(float) * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_y, sizeof(float) * n));
|
||||
|
||||
start_timer();
|
||||
int TILE = n / N_STREAMS;
|
||||
cudaStream_t stream[N_STREAMS];
|
||||
for(int i = 0; i < N_STREAMS; i++)
|
||||
cudaStreamCreate(&stream[i]);
|
||||
|
||||
//TODO Loop over the Tiles
|
||||
for (int i = 0; i < n; i += TILE)
|
||||
{
|
||||
//TODO Copy in Tile i (stream i)
|
||||
gpuErrchk(cudaMemcpyAsync(&d_x[i], &h_x[i], sizeof(float) * TILE, cudaMemcpyHostToDevice, stream[i/TILE]));
|
||||
gpuErrchk(cudaMemcpyAsync(&d_y[i], &h_y[i], sizeof(float) * TILE, cudaMemcpyHostToDevice, stream[i/TILE]));
|
||||
|
||||
//TODO Kernel Tile i (stream i)
|
||||
gpu_saxpy<<<((TILE + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE,0,stream[i/TILE]>>>(&d_y[i], a, &d_x[i], TILE);
|
||||
|
||||
//TODO Copy out Tile i (stream i)
|
||||
gpuErrchk(cudaMemcpyAsync(&h_y[i], &d_y[i], sizeof(float) * TILE, cudaMemcpyDeviceToHost,stream[i/TILE]));
|
||||
}
|
||||
//TODO Wait all the streams...
|
||||
cudaDeviceSynchronize();
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
free(h_x);
|
||||
gpuErrchk(cudaFree(d_x));
|
||||
free(h_y);
|
||||
gpuErrchk(cudaFree(d_y));
|
||||
free(h_z);
|
||||
|
||||
for (int i=0; i<N_STREAMS; ++i)
|
||||
cudaStreamDestroy(stream[i]);
|
||||
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
178
cuda/lab3/.solutions/saxpy-v5.cu
Normal file
178
cuda/lab3/.solutions/saxpy-v5.cu
Normal file
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (128)
|
||||
#endif
|
||||
|
||||
#ifndef N_STREAMS
|
||||
#define N_STREAMS (16)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float *__restrict__ y, float a, float *__restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd \
|
||||
: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float *__restrict__ y, float a, float *__restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x;
|
||||
float *h_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//CUDA Buffer Allocation
|
||||
gpuErrchk(cudaMallocManaged((void **)&h_x, sizeof(float) * n));
|
||||
gpuErrchk(cudaMallocManaged((void **)&h_y, sizeof(float) * n));
|
||||
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
gpuErrchk(cudaFree(h_x));
|
||||
gpuErrchk(cudaFree(h_y));
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
start_timer();
|
||||
int TILE = n / N_STREAMS;
|
||||
cudaStream_t stream[N_STREAMS];
|
||||
for (int i = 0; i < N_STREAMS; i++)
|
||||
cudaStreamCreate(&stream[i]);
|
||||
|
||||
//TODO Loop over the Tiles
|
||||
for (int i = 0; i < n; i += TILE)
|
||||
{
|
||||
//TODO Kernel Tile i (stream i)
|
||||
gpu_saxpy<<<((TILE + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE, 0, stream[i / TILE]>>>(&h_y[i], a, &h_x[i], TILE);
|
||||
}
|
||||
//TODO Wait all the streams...
|
||||
cudaDeviceSynchronize();
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float)elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float)elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
gpuErrchk(cudaFree(h_x));
|
||||
gpuErrchk(cudaFree(h_y));
|
||||
free(h_z);
|
||||
|
||||
for (int i = 0; i < N_STREAMS; ++i)
|
||||
cudaStreamDestroy(stream[i]);
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
240
cuda/lab3/.solutions/sobel-v1.cu
Normal file
240
cuda/lab3/.solutions/sobel-v1.cu
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sobel.cu
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Sobel Filtering
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgcodecs/imgcodecs.hpp>
|
||||
#include <opencv2/objdetect/objdetect.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE 16
|
||||
#endif
|
||||
#ifndef NSTREAMS
|
||||
#define NSTREAMS 12
|
||||
#endif
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
int FILTER_HOST[3][3] = {{-1, 0, 1},
|
||||
{-2, 0, 2},
|
||||
{-1, 0, 1}};
|
||||
|
||||
void sobel_host(unsigned char *__restrict__ orig, unsigned char *__restrict__ out, int width, int height)
|
||||
{
|
||||
#pragma omp parallel for collapse(2)
|
||||
for (int y = 1; y < height - 1; y++)
|
||||
{
|
||||
for (int x = 1; x < width - 1; x++)
|
||||
{
|
||||
int dx = 0, dy = 0;
|
||||
for (int k = -1; k <= 1; k++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
dx += FILTER_HOST[k + 1][z + 1] * orig[(y + k) * width + x + z];
|
||||
dy += FILTER_HOST[z + 1][k + 1] * orig[(y + k) * width + x + z];
|
||||
}
|
||||
}
|
||||
out[y * width + x] = sqrt((float)((dx * dx) + (dy * dy)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__constant__ int FILTER_GPU[3][3] = {{-1, 0, 1},
|
||||
{-2, 0, 2},
|
||||
{-1, 0, 1}};
|
||||
|
||||
__global__ void sobel_v1(unsigned char *__restrict__ orig, unsigned char *__restrict__ out, int width, int height)
|
||||
{
|
||||
int i = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
int j = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
|
||||
if (j > 0 && i > 0 && j < width - 1 && i < height - 1)
|
||||
{
|
||||
int dx = 0, dy = 0;
|
||||
for (int k = -1; k <= 1; k++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
dx += FILTER_GPU[k + 1][z + 1] * orig[(i + k) * width + j + z];
|
||||
dy += FILTER_GPU[z + 1][k + 1] * orig[(i + k) * width + j + z];
|
||||
}
|
||||
}
|
||||
out[i * width + j] = sqrt((float)((dx * dx) + (dy * dy)));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int iret = 0;
|
||||
struct timespec rt[2];
|
||||
string filename("data/sample.avi");
|
||||
|
||||
if (argc > 1)
|
||||
filename = argv[1];
|
||||
|
||||
//Open Video Example
|
||||
VideoCapture cap(filename);
|
||||
// Check if camera opened successfully
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cout << "Error opening video stream or file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int width = cap.get(CAP_PROP_FRAME_WIDTH);
|
||||
int height = cap.get(CAP_PROP_FRAME_HEIGHT);
|
||||
int nCh = 3;
|
||||
|
||||
// Frame Buffers
|
||||
Mat frameRGB = Mat::zeros(height, width, CV_8UC3);
|
||||
Mat frameIn = Mat::zeros(height, width, CV_8UC1);
|
||||
Mat frameOut = Mat::zeros(height, width, CV_8UC1);
|
||||
|
||||
int nFrames = 0;
|
||||
double time_cnt = 0.0;
|
||||
while (1)
|
||||
{
|
||||
bool lastFrame = cap.read(frameRGB); // read a new frame from video
|
||||
if (!lastFrame)
|
||||
break;
|
||||
|
||||
cvtColor(frameRGB, frameIn, COLOR_BGR2GRAY);
|
||||
|
||||
// Compute CPU Version - Golden Model
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
sobel_host(frameIn.ptr(), frameOut.ptr(), width, height);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
time_cnt+= (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
nFrames++;
|
||||
|
||||
#ifdef DISPLAY
|
||||
// Show frames
|
||||
imshow("frameIn", frameIn);
|
||||
imshow("frameOut", frameOut);
|
||||
waitKey(1);
|
||||
#endif
|
||||
}
|
||||
printf("Sobel (Host) : %d frames, %9.6f s per-frame (%9.6f fps)\n", nFrames, time_cnt/nFrames, 1/(time_cnt/nFrames));
|
||||
|
||||
// CUDA VERSION --------------------------------------------------
|
||||
//Open Video Example
|
||||
cap = VideoCapture(filename);
|
||||
// Check if camera opened successfully
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cout << "Error opening video stream or file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char *d_image_in;
|
||||
unsigned char *d_image_out;
|
||||
gpuErrchk(cudaMalloc((void **)&d_image_in, sizeof(unsigned char) * width * height));
|
||||
gpuErrchk(cudaMalloc((void **)&d_image_out, sizeof(unsigned char) * width * height));
|
||||
gpuErrchk(cudaMemset(d_image_out, 0, sizeof(unsigned char) * width * height));
|
||||
|
||||
cudaStream_t stream[NSTREAMS];
|
||||
for(int i = 0; i < NSTREAMS; i++)
|
||||
cudaStreamCreate(&stream[i]);
|
||||
|
||||
nFrames = 0;
|
||||
time_cnt = 0.0;
|
||||
while (1)
|
||||
{
|
||||
bool lastFrame = cap.read(frameRGB); // read a new frame from video
|
||||
if (!lastFrame)
|
||||
break;
|
||||
|
||||
cvtColor(frameRGB, frameIn, COLOR_BGR2GRAY);
|
||||
|
||||
// Compute CPU Version - Golden Model
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
gpuErrchk(cudaMemcpyAsync(d_image_in, frameIn.ptr(), sizeof(unsigned char) * width * height, cudaMemcpyHostToDevice,stream[nFrames%NSTREAMS]));
|
||||
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
|
||||
dim3 dimGrid((width + BLOCK_SIZE - 1) / BLOCK_SIZE, (height + BLOCK_SIZE - 1) / BLOCK_SIZE);
|
||||
sobel_v1<<<dimGrid, dimBlock,0,stream[nFrames%NSTREAMS]>>>(d_image_in, d_image_out, width, height);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
gpuErrchk(cudaMemcpyAsync(frameOut.ptr(), d_image_out, sizeof(unsigned char) * width * height, cudaMemcpyDeviceToHost,stream[nFrames%NSTREAMS]));
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
time_cnt+= (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
nFrames++;
|
||||
|
||||
#ifdef DISPLAY
|
||||
// Show frames
|
||||
imshow("frameIn", frameIn);
|
||||
imshow("frameOut", frameOut);
|
||||
waitKey(1);
|
||||
#endif
|
||||
}
|
||||
cudaDeviceSynchronize();
|
||||
printf("Sobel (GPU) : %d frames, %9.6f s per-frame (%9.6f fps)\n", nFrames, time_cnt/nFrames, 1/(time_cnt/nFrames));
|
||||
|
||||
gpuErrchk(cudaFree(d_image_out));
|
||||
gpuErrchk(cudaFree(d_image_in));
|
||||
for (int i=0; i<NSTREAMS; ++i)
|
||||
gpuErrchk(cudaStreamDestroy(stream[i]));
|
||||
|
||||
frameOut.release();
|
||||
frameIn.release();
|
||||
frameRGB.release();
|
||||
cap.release();
|
||||
|
||||
return iret;
|
||||
}
|
58
cuda/lab3/Makefile
Executable file
58
cuda/lab3/Makefile
Executable file
|
@ -0,0 +1,58 @@
|
|||
ifndef CUDA_HOME
|
||||
CUDA_HOME:=/usr/local/cuda
|
||||
endif
|
||||
|
||||
ifndef EXERCISE
|
||||
EXERCISE=exercise1.cu
|
||||
endif
|
||||
|
||||
BUILD_DIR ?= ./build
|
||||
|
||||
NVCC=$(CUDA_HOME)/bin/nvcc
|
||||
CXX=g++
|
||||
|
||||
OPT:=-O2 -g
|
||||
NVOPT:=-Xcompiler -fopenmp -lineinfo -arch=sm_53 --ptxas-options=-v --use_fast_math `pkg-config --cflags --libs opencv4`
|
||||
|
||||
CXXFLAGS:=$(OPT) -I. $(EXT_CXXFLAGS)
|
||||
LDFLAGS:=-lm -lcudart $(EXT_LDFLAGS)
|
||||
|
||||
NVCFLAGS:=$(CXXFLAGS) $(NVOPT)
|
||||
NVLDFLAGS:=$(LDFLAGS) -lgomp
|
||||
|
||||
SRCS:= utils.c
|
||||
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) $(EXERCISE:%=$(BUILD_DIR)/%.o)
|
||||
EXE=$(EXERCISE:.cu=.exe)
|
||||
|
||||
$(EXE): $(OBJS)
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(NVCC) $(NVCFLAGS) $(OBJS) -o $@ $(NVLDFLAGS)
|
||||
|
||||
$(BUILD_DIR)/%.cu.o: %.cu
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(NVCC) $(NVCFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.cpp.o: %.cpp
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(BUILD_DIR)/%.c.o: %.c
|
||||
$(MKDIR_P) $(dir $@)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
all: $(EXE)
|
||||
|
||||
.PHONY: run profile clean
|
||||
run: $(EXE)
|
||||
./$(EXE)
|
||||
|
||||
profile: $(EXE)
|
||||
sudo LD_LIBRARY_PATH=$(CUDA_HOME)/lib:/usr/ext/lib:${LD_LIBRARY_PATH} LIBRARY_PATH=/usr/ext/lib:${LIBRARY_PATH} nvprof ./$(EXE)
|
||||
|
||||
metrics: $(EXE)
|
||||
sudo LD_LIBRARY_PATH=$(CUDA_HOME)/lib:/usr/ext/lib:${LD_LIBRARY_PATH} LIBRARY_PATH=/usr/ext/lib:${LIBRARY_PATH} nvprof --print-gpu-trace --metrics "eligible_warps_per_cycle,achieved_occupancy,sm_efficiency,ipc" ./$(EXE)
|
||||
|
||||
clean:
|
||||
-rm -fr $(BUILD_DIR) *.exe *.out *~
|
||||
|
||||
MKDIR_P ?= mkdir -p
|
BIN
cuda/lab3/data/buzz.jpg
Normal file
BIN
cuda/lab3/data/buzz.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
BIN
cuda/lab3/data/daisy.jpg
Normal file
BIN
cuda/lab3/data/daisy.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
BIN
cuda/lab3/data/earth_rise.jpg
Normal file
BIN
cuda/lab3/data/earth_rise.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
BIN
cuda/lab3/data/fiore.jpg
Normal file
BIN
cuda/lab3/data/fiore.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 261 KiB |
BIN
cuda/lab3/data/sample.avi
Normal file
BIN
cuda/lab3/data/sample.avi
Normal file
Binary file not shown.
251
cuda/lab3/gemm.cu
Normal file
251
cuda/lab3/gemm.cu
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file gemm.cu
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief GEMM Kernel
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
|
||||
#ifndef N
|
||||
#define N (1 << 10)
|
||||
#endif
|
||||
#ifndef TILE_W
|
||||
#define TILE_W 128
|
||||
#endif
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE 32
|
||||
#endif
|
||||
|
||||
#define SM 64
|
||||
static void reorder(float *__restrict__ a, float *__restrict__ b, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
for (int j = 0; j < SM; j++)
|
||||
b[i * SM + j] = a[i * n + j];
|
||||
}
|
||||
|
||||
static void mm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
for (int i = 0; i < SM; i++)
|
||||
{
|
||||
for (int k = 0; k < SM; k++)
|
||||
{
|
||||
for (int j = 0; j < SM; j++)
|
||||
{
|
||||
c[i * n + j] += a[i * n + k] * b[k * SM + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void gemm_host(float *a, float *b, float *c, int n)
|
||||
{
|
||||
int bk = n / SM;
|
||||
#pragma omp parallel for collapse(3)
|
||||
for (int i = 0; i < bk; i++)
|
||||
{
|
||||
for (int j = 0; j < bk; j++)
|
||||
{
|
||||
for (int k = 0; k < bk; k++)
|
||||
{
|
||||
float b2[SM * SM];
|
||||
reorder(&b[SM * (k * n + j)], b2, n);
|
||||
mm(&a[SM * (i * n + k)], b2, &c[SM * (i * n + j)], n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
__global__ void gemm(float *__restrict__ a, float *__restrict__ b, float *__restrict__ c, int n)
|
||||
{
|
||||
__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
|
||||
__shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];
|
||||
|
||||
int ib = blockIdx.y;
|
||||
int jb = blockIdx.x;
|
||||
|
||||
int it = threadIdx.y;
|
||||
int jt = threadIdx.x;
|
||||
|
||||
int a_offset, b_offset, c_offset;
|
||||
|
||||
float Cvalue = 0.0f;
|
||||
for (int kb = 0; kb < (n / BLOCK_SIZE); ++kb)
|
||||
{
|
||||
a_offset = ib * n * BLOCK_SIZE + kb * BLOCK_SIZE;
|
||||
b_offset = kb * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
As[it][jt] = a[a_offset + it * n + jt];
|
||||
Bs[it][jt] = b[b_offset + it * n + jt];
|
||||
__syncthreads();
|
||||
|
||||
for (int k = 0; k < BLOCK_SIZE; ++k)
|
||||
Cvalue += As[it][k] * Bs[k][jt];
|
||||
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
c_offset = ib * n * BLOCK_SIZE + jb * BLOCK_SIZE;
|
||||
c[c_offset + it * n + jt] = Cvalue;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int n = N, iret = 0;
|
||||
float *a, *b, *c, *g;
|
||||
struct timespec rt[2];
|
||||
double wt; // walltime
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
if (NULL == (a = (float *)malloc(sizeof(*a) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'x'\n");
|
||||
iret = -1;
|
||||
}
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
if (NULL == (b = (float *)malloc(sizeof(*b) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'y'\n");
|
||||
iret = -1;
|
||||
}
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
if (NULL == (c = (float *)malloc(sizeof(*c) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (g = (float *)malloc(sizeof(*g) * n * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
|
||||
if (0 != iret)
|
||||
{
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(a);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(b);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(c);
|
||||
free(g);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
int _b = rand() % TWO04;
|
||||
int _c = rand() % TWO08;
|
||||
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
a[i] = _b / (float)TWO02;
|
||||
b[i] = _c / (float)TWO04;
|
||||
c[i] = g[i] = 0.0;
|
||||
}
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
gemm_host(a, b, g, n);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM (Host) : %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
//TODO Remove if unecessary
|
||||
float *d_a, *d_b, *d_c;
|
||||
gpuErrchk(cudaMalloc((void **)&d_a, sizeof(float) * n * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_b, sizeof(float) * n * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_c, sizeof(float) * n * n));
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(d_a, a, sizeof(float) * n * n, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpy(d_b, b, sizeof(float) * n * n, cudaMemcpyHostToDevice));
|
||||
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
|
||||
dim3 dimGrid((n + (BLOCK_SIZE)-1) / (BLOCK_SIZE), (n + (BLOCK_SIZE)-1) / (BLOCK_SIZE));
|
||||
gemm<<<dimGrid, dimBlock>>>(d_a, d_b, d_c, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(c, d_c, sizeof(float) * n * n, cudaMemcpyDeviceToHost));
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
wt = (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
printf("GEMM-v1 (GPU): %9.3f sec %9.1f GFLOPS\n", wt, 2.0 * n * n * n / (1.0e9 * wt));
|
||||
|
||||
for (int i = 0; i < n * n; i++)
|
||||
{
|
||||
iret = *(int *)(g + i) ^ *(int *)(c + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(a);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(b);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(c);
|
||||
free(g);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_a));
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_b));
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_c));
|
||||
|
||||
return 0;
|
||||
}
|
184
cuda/lab3/saxpy.cu
Normal file
184
cuda/lab3/saxpy.cu
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file saxpy.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Saxpy
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
#define TWO02 (1 << 2)
|
||||
#define TWO04 (1 << 4)
|
||||
#define TWO08 (1 << 8)
|
||||
#ifndef N
|
||||
#define N (1 << 27)
|
||||
#endif
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE (512)
|
||||
#endif
|
||||
|
||||
/*
|
||||
*SAXPY (host implementation)
|
||||
* y := a * x + y
|
||||
*/
|
||||
void host_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
#pragma omp parallel for simd schedule(simd: static)
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void gpu_saxpy(float * __restrict__ y, float a, float * __restrict__ x, int n)
|
||||
{
|
||||
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
if (i < n)
|
||||
y[i] = a * x[i] + y[i];
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int iret = 0;
|
||||
int n = N;
|
||||
float *h_x, *d_x;
|
||||
float *h_y, *d_y;
|
||||
float *h_z;
|
||||
float a = 101.0f / TWO02,
|
||||
b, c;
|
||||
|
||||
if (argc > 1)
|
||||
n = atoi(argv[1]);
|
||||
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
if (NULL == (h_x = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'x'\n");
|
||||
iret = -1;
|
||||
}
|
||||
//TODO Update malloc to cudaMallocHost or cudaMallocManaged (if necessary)
|
||||
if (NULL == (h_y = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'y'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (NULL == (h_z = (float *)malloc(sizeof(float) * n)))
|
||||
{
|
||||
printf("error: memory allocation for 'z'\n");
|
||||
iret = -1;
|
||||
}
|
||||
if (0 != iret)
|
||||
{
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(h_x);
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(h_y);
|
||||
free(h_z);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//Init Data
|
||||
b = rand() % TWO04;
|
||||
c = rand() % TWO08;
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
h_x[i] = b / (float)TWO02;
|
||||
h_y[i] = h_z[i] = c / (float)TWO04;
|
||||
}
|
||||
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMalloc((void **)&d_x, sizeof(float) * n));
|
||||
gpuErrchk(cudaMalloc((void **)&d_y, sizeof(float) * n));
|
||||
|
||||
start_timer();
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(d_x, h_x, sizeof(float) * n, cudaMemcpyHostToDevice));
|
||||
gpuErrchk(cudaMemcpy(d_y, h_y, sizeof(float) * n, cudaMemcpyHostToDevice));
|
||||
gpu_saxpy<<<((n + BLOCK_SIZE - 1) / BLOCK_SIZE), BLOCK_SIZE>>>(d_y, a, d_x, n);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaMemcpy(h_y, d_y, sizeof(float) * n, cudaMemcpyDeviceToHost));
|
||||
stop_timer();
|
||||
printf("saxpy (GPU): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
|
||||
//Check Matematical Consistency
|
||||
start_timer();
|
||||
host_saxpy(h_z, a, h_x, n);
|
||||
stop_timer();
|
||||
printf("saxpy (Host): %9.3f sec %9.1f GFLOPS\n", elapsed_ns() / 1.0e9, 2 * n / ((float) elapsed_ns()));
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
iret = *(int *)(h_y + i) ^ *(int *)(h_z + i);
|
||||
assert(iret == 0);
|
||||
}
|
||||
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(h_x);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_x));
|
||||
//TODO Update cudaFreeHost or cudaFree (if necessary)
|
||||
free(h_y);
|
||||
//TODO Remove if unecessary
|
||||
gpuErrchk(cudaFree(d_y));
|
||||
free(h_z);
|
||||
|
||||
// CUDA exit -- needed to flush printf write buffer
|
||||
cudaDeviceReset();
|
||||
return 0;
|
||||
}
|
229
cuda/lab3/sobel.cu
Normal file
229
cuda/lab3/sobel.cu
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file sobel.cu
|
||||
* @author Alessandro Capotondi
|
||||
* @date 12 May 2020
|
||||
* @brief Sobel Filtering
|
||||
*
|
||||
* @see https://dolly.fim.unimore.it/2019/course/view.php?id=152
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <opencv2/imgcodecs/imgcodecs.hpp>
|
||||
#include <opencv2/objdetect/objdetect.hpp>
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
|
||||
using namespace cv;
|
||||
using namespace std;
|
||||
|
||||
#ifndef BLOCK_SIZE
|
||||
#define BLOCK_SIZE 32
|
||||
#endif
|
||||
|
||||
#define gpuErrchk(ans) \
|
||||
{ \
|
||||
gpuAssert((ans), __FILE__, __LINE__); \
|
||||
}
|
||||
static inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort = true)
|
||||
{
|
||||
if (code != cudaSuccess)
|
||||
{
|
||||
fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
|
||||
if (abort)
|
||||
exit(code);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "utils.h"
|
||||
}
|
||||
|
||||
int FILTER_HOST[3][3] = {{-1, 0, 1},
|
||||
{-2, 0, 2},
|
||||
{-1, 0, 1}};
|
||||
|
||||
void sobel_host(unsigned char *__restrict__ orig, unsigned char *__restrict__ out, int width, int height)
|
||||
{
|
||||
#pragma omp parallel for collapse(2)
|
||||
for (int y = 1; y < height - 1; y++)
|
||||
{
|
||||
for (int x = 1; x < width - 1; x++)
|
||||
{
|
||||
int dx = 0, dy = 0;
|
||||
for (int k = -1; k <= 1; k++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
dx += FILTER_HOST[k + 1][z + 1] * orig[(y + k) * width + x + z];
|
||||
dy += FILTER_HOST[z + 1][k + 1] * orig[(y + k) * width + x + z];
|
||||
}
|
||||
}
|
||||
out[y * width + x] = sqrt((float)((dx * dx) + (dy * dy)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__constant__ int FILTER_GPU[3][3] = {{-1, 0, 1},
|
||||
{-2, 0, 2},
|
||||
{-1, 0, 1}};
|
||||
|
||||
__global__ void sobel_v1(unsigned char *__restrict__ orig, unsigned char *__restrict__ out, int width, int height)
|
||||
{
|
||||
int i = threadIdx.y + blockIdx.y * blockDim.y;
|
||||
int j = threadIdx.x + blockIdx.x * blockDim.x;
|
||||
|
||||
if (j > 0 && i > 0 && j < width - 1 && i < height - 1)
|
||||
{
|
||||
int dx = 0, dy = 0;
|
||||
for (int k = -1; k <= 1; k++)
|
||||
{
|
||||
for (int z = -1; z <= 1; z++)
|
||||
{
|
||||
dx += FILTER_GPU[k + 1][z + 1] * orig[(i + k) * width + j + z];
|
||||
dy += FILTER_GPU[z + 1][k + 1] * orig[(i + k) * width + j + z];
|
||||
}
|
||||
}
|
||||
out[i * width + j] = sqrt((float)((dx * dx) + (dy * dy)));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int iret = 0;
|
||||
struct timespec rt[2];
|
||||
string filename("data/sample.avi");
|
||||
|
||||
if (argc > 1)
|
||||
filename = argv[1];
|
||||
|
||||
//Open Video Example
|
||||
VideoCapture cap(filename);
|
||||
// Check if camera opened successfully
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cout << "Error opening video stream or file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int width = cap.get(CAP_PROP_FRAME_WIDTH);
|
||||
int height = cap.get(CAP_PROP_FRAME_HEIGHT);
|
||||
int nCh = 3;
|
||||
|
||||
// Frame Buffers
|
||||
Mat frameRGB = Mat::zeros(height, width, CV_8UC3);
|
||||
Mat frameIn = Mat::zeros(height, width, CV_8UC1);
|
||||
Mat frameOut = Mat::zeros(height, width, CV_8UC1);
|
||||
|
||||
int nFrames = 0;
|
||||
double time_cnt = 0.0;
|
||||
while (1)
|
||||
{
|
||||
bool lastFrame = cap.read(frameRGB); // read a new frame from video
|
||||
if (!lastFrame)
|
||||
break;
|
||||
|
||||
cvtColor(frameRGB, frameIn, COLOR_BGR2GRAY);
|
||||
|
||||
// Compute CPU Version - Golden Model
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
sobel_host(frameIn.ptr(), frameOut.ptr(), width, height);
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
time_cnt+= (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
nFrames++;
|
||||
|
||||
#ifdef DISPLAY
|
||||
// Show frames
|
||||
imshow("frameIn", frameIn);
|
||||
imshow("frameOut", frameOut);
|
||||
waitKey(1);
|
||||
#endif
|
||||
}
|
||||
printf("Sobel (Host) : %d frames, %9.6f s per-frame (%9.6f fps)\n", nFrames, time_cnt/nFrames, 1/(time_cnt/nFrames));
|
||||
|
||||
// CUDA VERSION --------------------------------------------------
|
||||
//Open Video Example
|
||||
cap = VideoCapture(filename);
|
||||
// Check if camera opened successfully
|
||||
if (!cap.isOpened())
|
||||
{
|
||||
cout << "Error opening video stream or file" << endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned char *d_image_in;
|
||||
unsigned char *d_image_out;
|
||||
gpuErrchk(cudaMalloc((void **)&d_image_in, sizeof(unsigned char) * width * height));
|
||||
gpuErrchk(cudaMalloc((void **)&d_image_out, sizeof(unsigned char) * width * height));
|
||||
gpuErrchk(cudaMemset(d_image_out, 0, sizeof(unsigned char) * width * height));
|
||||
|
||||
nFrames = 0;
|
||||
time_cnt = 0.0;
|
||||
while (1)
|
||||
{
|
||||
bool lastFrame = cap.read(frameRGB); // read a new frame from video
|
||||
if (!lastFrame)
|
||||
break;
|
||||
|
||||
cvtColor(frameRGB, frameIn, COLOR_BGR2GRAY);
|
||||
|
||||
// Compute CPU Version - Golden Model
|
||||
clock_gettime(CLOCK_REALTIME, rt + 0);
|
||||
gpuErrchk(cudaMemcpy(d_image_in, frameIn.ptr(), sizeof(unsigned char) * width * height, cudaMemcpyHostToDevice));
|
||||
dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
|
||||
dim3 dimGrid((width + BLOCK_SIZE - 1) / BLOCK_SIZE, (height + BLOCK_SIZE - 1) / BLOCK_SIZE);
|
||||
sobel_v1<<<dimGrid, dimBlock>>>(d_image_in, d_image_out, width, height);
|
||||
gpuErrchk(cudaPeekAtLastError());
|
||||
gpuErrchk(cudaMemcpy(frameOut.ptr(), d_image_out, sizeof(unsigned char) * width * height, cudaMemcpyDeviceToHost));
|
||||
clock_gettime(CLOCK_REALTIME, rt + 1);
|
||||
time_cnt+= (rt[1].tv_sec - rt[0].tv_sec) + 1.0e-9 * (rt[1].tv_nsec - rt[0].tv_nsec);
|
||||
nFrames++;
|
||||
|
||||
#ifdef DISPLAY
|
||||
// Show frames
|
||||
imshow("frameIn", frameIn);
|
||||
imshow("frameOut", frameOut);
|
||||
waitKey(1);
|
||||
#endif
|
||||
}
|
||||
printf("Sobel (GPU) : %d frames, %9.6f s per-frame (%9.6f fps)\n", nFrames, time_cnt/nFrames, 1/(time_cnt/nFrames));
|
||||
|
||||
gpuErrchk(cudaFree(d_image_out));
|
||||
gpuErrchk(cudaFree(d_image_in));
|
||||
frameOut.release();
|
||||
frameIn.release();
|
||||
frameRGB.release();
|
||||
cap.release();
|
||||
|
||||
return iret;
|
||||
}
|
138
cuda/lab3/utils.c
Normal file
138
cuda/lab3/utils.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/**
|
||||
* @file utils.c
|
||||
* @author Alessandro Capotondi
|
||||
* @date 27 Mar 2020
|
||||
* @brief File containing utilities functions for HPC Unimore Class
|
||||
*
|
||||
* Utilities for OpenMP lab.
|
||||
*
|
||||
* @see http://algo.ing.unimo.it/people/andrea/Didattica/HPC/index.html
|
||||
*/
|
||||
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MAX_ITERATIONS 100
|
||||
static struct timespec timestampA, timestampB;
|
||||
static unsigned long long statistics[MAX_ITERATIONS];
|
||||
static int iterations = 0;
|
||||
|
||||
static unsigned long long __diff_ns(struct timespec start, struct timespec end)
|
||||
{
|
||||
struct timespec temp;
|
||||
if ((end.tv_nsec - start.tv_nsec) < 0)
|
||||
{
|
||||
temp.tv_sec = end.tv_sec - start.tv_sec - 1;
|
||||
temp.tv_nsec = 1000000000ULL + end.tv_nsec - start.tv_nsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.tv_sec = end.tv_sec - start.tv_sec;
|
||||
temp.tv_nsec = end.tv_nsec - start.tv_nsec;
|
||||
}
|
||||
|
||||
return temp.tv_nsec + temp.tv_sec * 1000000000ULL;
|
||||
}
|
||||
|
||||
void start_timer()
|
||||
{
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, ×tampA);
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void stop_timer()
|
||||
{
|
||||
unsigned long long elapsed = 0ULL;
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, ×tampB);
|
||||
asm volatile("" ::
|
||||
: "memory");
|
||||
}
|
||||
|
||||
unsigned long long elapsed_ns()
|
||||
{
|
||||
return __diff_ns(timestampA, timestampB);
|
||||
}
|
||||
|
||||
void start_stats()
|
||||
{
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void collect_stats()
|
||||
{
|
||||
assert(iterations < MAX_ITERATIONS);
|
||||
stop_timer();
|
||||
statistics[iterations++] = elapsed_ns();
|
||||
}
|
||||
|
||||
void print_stats()
|
||||
{
|
||||
unsigned long long min = ULLONG_MAX;
|
||||
unsigned long long max = 0LL;
|
||||
double average = 0.0;
|
||||
double std_deviation = 0.0;
|
||||
double sum = 0.0;
|
||||
|
||||
/* Compute the sum of all elements */
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
if (statistics[i] > max)
|
||||
max = statistics[i];
|
||||
if (statistics[i] < min)
|
||||
min = statistics[i];
|
||||
sum = sum + statistics[i] / 1E6;
|
||||
}
|
||||
average = sum / (double)iterations;
|
||||
|
||||
/* Compute variance and standard deviation */
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
sum = sum + pow((statistics[i] / 1E6 - average), 2);
|
||||
}
|
||||
std_deviation = sqrt(sum / (double)iterations);
|
||||
|
||||
printf("AvgTime\tMinTime\tMaxTime\tStdDev\n");
|
||||
printf("%.4f ms\t%.4f ms\t%.4f ms\t%.4f\n", (double)average, (double)min / 1E6, (double)max / 1E6, (double)std_deviation);
|
||||
}
|
||||
|
||||
}
|
142
cuda/lab3/utils.h
Normal file
142
cuda/lab3/utils.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* BSD 2-Clause License
|
||||
*
|
||||
* Copyright (c) 2020, Alessandro Capotondi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file utils.h
|
||||
* @author Alessandro Capotondi
|
||||
* @date 27 Mar 2020
|
||||
* @brief File containing utilities functions for HPC Unimore Class
|
||||
*
|
||||
* The header define time functions and dummy workload used on the example tests.
|
||||
*
|
||||
* @see http://algo.ing.unimo.it/people/andrea/Didattica/HPC/index.html
|
||||
*/
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(VERBOSE)
|
||||
#define DEBUG_PRINT(x, ...) printf((x), ##__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINT(x, ...)
|
||||
#endif
|
||||
|
||||
#if !defined(NTHREADS)
|
||||
#define NTHREADS (4)
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief The function set the timestampA
|
||||
*
|
||||
* The function is used to measure elapsed time between two execution points.
|
||||
* The function start_timer() sets the starting point timestamp, while the function
|
||||
* stop_timer() sets the termination timestamp. The elapsed time, expressed in nanoseconds,
|
||||
* between the two points can be retrieved using the function elapsed_ns().
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* start_timer(); // Point A
|
||||
* //SOME CODE HERE
|
||||
* stop_timer(); // Point B
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and B
|
||||
* //SOME OTHER CODE HERE
|
||||
* stop_timer(); // Point C
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and C
|
||||
* @endcode
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
* @see elapsed_ns()
|
||||
*/
|
||||
void start_timer();
|
||||
|
||||
/**
|
||||
* @brief The function set the second timestamps
|
||||
*
|
||||
* The function is used to measure elapsed time between two execution points.
|
||||
* The function start_timer() sets the starting point timestamp, while the function
|
||||
* stop_timer() returns the elapsed time, expressed in nanoseconds between the last call
|
||||
* of start_timer() and the current execution point.
|
||||
*
|
||||
* Example usage:
|
||||
* @code
|
||||
* start_timer(); // Point A
|
||||
* //SOME CODE HERE
|
||||
* stop_timer(); // Point B
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and B
|
||||
* //SOME OTHER CODE HERE
|
||||
* stop_timer(); // Point C
|
||||
* printf("Elapsed time = %llu ns\n", elapsed_ns())); //Elapsed time between A and C
|
||||
* @endcode
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
* @see elapsed_ns()
|
||||
*/
|
||||
void stop_timer();
|
||||
|
||||
/**
|
||||
* @brief Elapsed nano seconds between start_timer() and stop_timer().
|
||||
*
|
||||
* @return Elapsed nano seconds
|
||||
* @see start_timer()
|
||||
* @see stop_timer()
|
||||
*/
|
||||
unsigned long long elapsed_ns();
|
||||
|
||||
/**
|
||||
* @brief The function init the starting point of stat measurement.
|
||||
*
|
||||
* The function is similar to start_timer().
|
||||
*
|
||||
* @return void
|
||||
* @see start_timer
|
||||
*/
|
||||
void start_stats();
|
||||
|
||||
/**
|
||||
* @brief The function collects the elapsed time between the current exeuction point and the
|
||||
* last call of start_stats().
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
void collect_stats();
|
||||
|
||||
/**
|
||||
* @brief The function display the collected statistics.
|
||||
* @return void
|
||||
*/
|
||||
void print_stats();
|
||||
}
|
||||
#endif /*__UTILS_H__*/
|
Loading…
Reference in a new issue