This site contains OpenCL notes, tutorials, benchmarks, news.

Saturday, June 1, 2013

Tutorial: Simple start with OpenCL and C++

To begin programming in OpenCL is always hard. Let's try with the basic example. We want to sum two arrays together.

At first you need to install the OpenCL libraries and other files. AMD has for CPU's and their GPU's  AMD APP: http://developer.amd.com/tools-and-sdks/heterogeneous-computing/amd-accelerated-parallel-processing-app-sdk/downloads/. Intel has their OpenCL libraries at http://software.intel.com/en-us/vcsource/tools/opencl-sdk. And Nvidia has everything at https://developer.nvidia.com/cuda-downloads. In some cases the graphic drivers already include all the files you need. I recommend that you continue with the next step and if anything will go wrong return to this step and install the needed OpenCL SDK toolkits.



We will program in C++11. To ease everything we will use OpenCL C++ binding 1.1 from www.khronos.org/registry/cl/api/1.1/cl.hpp . manual for this binding is available at www.khronos.org/registry/cl/specs/opencl-cplusplus-1.1.pdf. It might happen that cl.hpp is already installed at your computer. If not then simply download C++ binding to folder of your project. Don't forget to turn on the C++11. In case of QtCreator add next line into the .pro file:
  QMAKE_CXXFLAGS += -std=c++0x
Also don't forget to use OpenCL library. In case of QtCreator add next line into the .pro file:
  LIBS+= -lOpenCL  
If you get any errors you need to adjust system variable to point to folder of OpenCL installation. You can also manually set path to OpenCL library path:
  LIBS+= -Lpath_to_openCL_libraries
Or you can simply write hard-coded path to OpenCL library:
  LIBS+=/usr/.../libOpenCL.so 
Let's start with coding. We will create simple console program which will use OpenCL to sum two arrays like C=A+B. For our simple sample we will need only two headers:
#include <iostream>
#include <CL/cl.hpp>
Everything else will happen inside main function. At start we need to get one of the OpenCL platforms. This is actually a driver you had previously installed. So platform can be from Nvidia, Intel, AMD....
int main(){
    //get all platforms (drivers)
    std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);
    if(all_platforms.size()==0){
        std::cout<<" No platforms found. Check OpenCL installation!\n";
        exit(1);
    }
    cl::Platform default_platform=all_platforms[0];
    std::cout << "Using platform: "<<default_platform.getInfo<CL_PLATFORM_NAME>()<<"\n";

Once we selected the first platform (default_platform) we will use it in the next steps. Now we need to get device of our platform. For example AMD's platform has support for multiple devices (CPU's and GPU's). We will now select the first device (default_device):
    //get default device of the default platform
    std::vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
    if(all_devices.size()==0){
        std::cout<<" No devices found. Check OpenCL installation!\n";
        exit(1);
    }
    cl::Device default_device=all_devices[0];
    std::cout<< "Using device: "<<default_device.getInfo<CL_DEVICE_NAME>()<<"\n";

Now we need to create a Context. Imagine the Context as the runtime link to the our device and platform:
    cl::Context context({default_device});

Next we need to create the program which we want to execute on our device:
    cl::Program::Sources sources;

Actual source of our program(kernel) is there:
    // kernel calculates for each element C=A+B
    std::string kernel_code=
            "   void kernel simple_add(global const int* A, global const int* B, global int* C){       "
            "       C[get_global_id(0)]=A[get_global_id(0)]+B[get_global_id(0)];                 "
            "   }                                                                               ";                                                                          ";
This code simply calculates C=A+B. As we want that one thread calculates sum of only one element, we use get_global_id(0). get_global_id(0) means get id of current thread. Id's can go from 0 to get_global_size(0) - 1. get_global_size(0) means number of threads. What is 0? 0 means first dimension. OpenCL supports running kernels on 1D, 2D and 3D problems. We will use 1D array! This means 1D problem. 

Next we need our kernel sources to build. We also check for the errors at building:
    sources.push_back({kernel_code.c_str(),kernel_code.length()});

    cl::Program program(context,sources);
    if(program.build({default_device})!=CL_SUCCESS){
        std::cout<<" Error building: "<<program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<<"\n";
        exit(1);
    }
For arrays A, B, C we need to allocate the space on the device:
    // create buffers on the device
    cl::Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*10);
    cl::Buffer buffer_B(context,CL_MEM_READ_WRITE,sizeof(int)*10);
    cl::Buffer buffer_C(context,CL_MEM_READ_WRITE,sizeof(int)*10);
Arrays will have 10 element. We want to calculate sum of next arrays (A, B).
    int A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int B[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0};
We need to copy arrays from A and B to the device. This means that we will copy arrays from the host to the device. Host represents our main. At first we need to create a queue which is the queue to the commands we will send to the our device:
    //create queue to which we will push commands for the device.
    cl::CommandQueue queue(context,default_device);
Now we can copy data from arrays A and B to buffer_A and buffer_B which represent memory on the device:
    //write arrays A and B to the device
    queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*10,A);
    queue.enqueueWriteBuffer(buffer_B,CL_TRUE,0,sizeof(int)*10,B);
Now we can run the kernel which in parallel sums A and B and writes to C. We do this with KernelFunctor which runs the kernel on the device. Take a look at the "simple_add" this is the name of our kernel we wrote before. You can see the number 10. This corresponds to number of threads we want to run (our array size is 10):

    cl::KernelFunctor simple_add(cl::Kernel(program,"simple_add"),queue,cl::NullRange,cl::NDRange(10),cl::NullRange);
Here we actually set the arguments to kernel simple_add and run the kernel:
    simple_add(buffer_A, buffer_B, buffer_C);
At the end we want to print memory C on our device. At first we need to transfer data from the device to our program (host):
    int C[10];
    //read result C from the device to array C
    queue.enqueueReadBuffer(buffer_C,CL_TRUE,0,sizeof(int)*10,C);

    std::cout<<" result: \n";
    for(int i=0;i<10;i++){
        std::cout<<C[i]<<" ";
    }

    return 0;
}

This is it. Complete code is there:


#include <iostream>
#include <CL/cl.hpp>

int main(){
    //get all platforms (drivers)
    std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);
    if(all_platforms.size()==0){
        std::cout<<" No platforms found. Check OpenCL installation!\n";
        exit(1);
    }
    cl::Platform default_platform=all_platforms[0];
    std::cout << "Using platform: "<<default_platform.getInfo<CL_PLATFORM_NAME>()<<"\n";

    //get default device of the default platform
    std::vector<cl::Device> all_devices;
    default_platform.getDevices(CL_DEVICE_TYPE_ALL, &all_devices);
    if(all_devices.size()==0){
        std::cout<<" No devices found. Check OpenCL installation!\n";
        exit(1);
    }
    cl::Device default_device=all_devices[0];
    std::cout<< "Using device: "<<default_device.getInfo<CL_DEVICE_NAME>()<<"\n";


    cl::Context context({default_device});

    cl::Program::Sources sources;

    // kernel calculates for each element C=A+B
    std::string kernel_code=
            "   void kernel simple_add(global const int* A, global const int* B, global int* C){       "
            "       C[get_global_id(0)]=A[get_global_id(0)]+B[get_global_id(0)];                 "
            "   }                                                                               ";
    sources.push_back({kernel_code.c_str(),kernel_code.length()});

    cl::Program program(context,sources);
    if(program.build({default_device})!=CL_SUCCESS){
        std::cout<<" Error building: "<<program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(default_device)<<"\n";
        exit(1);
    }


    // create buffers on the device
    cl::Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*10);
    cl::Buffer buffer_B(context,CL_MEM_READ_WRITE,sizeof(int)*10);
    cl::Buffer buffer_C(context,CL_MEM_READ_WRITE,sizeof(int)*10);

    int A[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int B[] = {0, 1, 2, 0, 1, 2, 0, 1, 2, 0};

    //create queue to which we will push commands for the device.
    cl::CommandQueue queue(context,default_device);

    //write arrays A and B to the device
    queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*10,A);
    queue.enqueueWriteBuffer(buffer_B,CL_TRUE,0,sizeof(int)*10,B);


    //run the kernel
    cl::KernelFunctor simple_add(cl::Kernel(program,"simple_add"),queue,cl::NullRange,cl::NDRange(10),cl::NullRange);
    simple_add(buffer_A,buffer_B,buffer_C);

    //alternative way to run the kernel
    /*cl::Kernel kernel_add=cl::Kernel(program,"simple_add");
    kernel_add.setArg(0,buffer_A);
    kernel_add.setArg(1,buffer_B);
    kernel_add.setArg(2,buffer_C);
    queue.enqueueNDRangeKernel(kernel_add,cl::NullRange,cl::NDRange(10),cl::NullRange);
    queue.finish();*/

    int C[10];
    //read result C from the device to array C
    queue.enqueueReadBuffer(buffer_C,CL_TRUE,0,sizeof(int)*10,C);

    std::cout<<" result: \n";
    for(int i=0;i<10;i++){
        std::cout<<C[i]<<" ";
    }

    return 0;
}

458 comments:

  1. Hi,

    thanks for the tutorial.
    To make it work with OpenCL 1.2 and corresponding cl.hpp:

    //run the kernel
    //cl 1.1
    //cl::KernelFunctor simple_add(cl::Kernel(program,"simple_add"),queue,cl::NullRange,cl::NDRange(10),cl::NullRange);
    //simple_add(buffer_A,buffer_B,buffer_C);

    //cl 1.2
    cl::make_kernel simple_add(cl::Kernel(program,"simple_add"));
    cl::EnqueueArgs eargs(queue,cl::NullRange,cl::NDRange(10),cl::NullRange);
    simple_add(eargs, buffer_A,buffer_B,buffer_C).wait();

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. cl::make_kernel needs template arguments, but I think anything between angle brackets gets eaten, which is probably why stéphane's code came out looking wrong. In this example, they need to be cl::Buffer& repeated three times (two input buffers, one output buffer).

      Sorry, too lazy to figure out the mark-up for embedded code.

      Delete
    3. //run the kernel
      auto simple_add = cl::make_kernel(program, "simple_add");
      cl::EnqueueArgs eargs(queue,cl::NullRange,cl::NDRange(10),cl::NullRange);
      simple_add(eargs, buffer_A,buffer_B,buffer_C).wait();

      Overwrite line 61-62 with this for opencl 1.2 works.

      Delete
    4. Thanks a lot!! This was extremely helpful

      Delete
    5. Hi, I use opencl 2.1 and I replaced line 61-62 with:

      cl::make_kernel simple_add(cl::Kernel(program, "simple_add"));
      cl::EnqueueArgs eargs(queue, cl::NullRange, cl::NDRange(10), cl::NullRange);
      simple_add(eargs, buffer_A, buffer_B, buffer_C).wait();

      Note that different from cl1.2, the cl::make_kernel is a class template, so there follows "".

      Delete
    6. For OpenCL 1.2, use the "Alternative Way" to run the kernel given in the complete code example of the original tutorial:

      cl::Kernel kernel_add=cl::Kernel(program,"simple_add"); kernel_add.setArg(0,buffer_A);
      kernel_add.setArg(1,buffer_B);
      kernel_add.setArg(2,buffer_C);

      queue.enqueueNDRangeKernel(kernel_add,cl::NullRange,cl::NDRange(10),cl::NullRange);

      queue.finish();

      Also, define the macro CL_USE_DEPRECATED_OPENCL_1_2_APIS at the beginning of your code:

      #define CL_USE_DEPRECATED_OPENCL_1_2_APIS


      (The other methods above require class template arguments)

      Delete
  2. Wow a very concise and easy to understand example. Thank you!

    ReplyDelete
  3. it is possible to bind C code or embedded C Code ..???

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Thank you for this tutorial. Unfortunately there is a problem using it with the current NVIDIA OpenCL ICD (the library that dispatches API calls to the appropriate driver), which is a missing function in the context of cl::Device. You can fix this by placing

    #define CL_USE_DEPRECATED_OPENCL_1_1_APIS
    #include iostream
    #include CL/cl.h
    #undef CL_VERSION_1_2
    #include CL/cl.hpp

    where filenames need to be embraced by < and >, at the very beginning.

    ReplyDelete
  6. Very helpful introduction to OpenCL, thank you!

    ReplyDelete
  7. Several errors occur when running this code. Where can be a problem? Thanks in advance.

    Error 1 error C2661: 'std::vector<_Ty>::push_back' : no overloaded function takes 2 arguments c:\xxxx\sumadd.cpp 34

    Error 2 error C2664: 'cl_int cl::Program::build(const std::vector<_Ty> &,const char *,void (__stdcall *)(cl_program,void *),void *) const' : cannot convert parameter 1 from 'cl::Device' to 'const std::vector<_Ty> &' c:\xxxx\sumadd.cpp 37

    3 IntelliSense: no instance of overloaded function "std::vector<_Ty, _Alloc>::push_back [with _Ty=std::pair, _Alloc=std::allocator>]" matches the argument list
    argument types are: (const char *, size_t)
    object type is: cl::Program::Sources c:\xxxx\SumAdd.cpp 34


    4 IntelliSense: no instance of overloaded function "cl::Program::build" matches the argument list
    argument types are: (cl::Device)
    object type is: cl::Program c:\xxxx\SumAdd.cpp 37

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. // add to the top
      #include < vector > (without the spaces)

      Delete
  8. Does OpenCL have any trait associated with it that would allow me to use a Macro to determine if OpenCL is available or not through my C++ code?
    Eg.
    #ifdef OPENCL

    ReplyDelete
  9. Great blog ! Keep writing !

    ReplyDelete
  10. I followed this example and I am now able to debug my open cl program! (in a crude way by writing values to a buffer... but it works!)

    thanks, great post

    ReplyDelete
  11. Thanks for sharing this useful information. Keep up the good work
    DevOps Online Training

    ReplyDelete
  12. Thanks you for sharing this unique useful information content with us.
    Datastage Online Training



    ReplyDelete
  13. It is wonderful. I was able to run the whole code with little tweeks with Visual Studio 2015. Thanks :)

    ReplyDelete
  14. I am obliged to you for sharing this piece of information here and updating us with your resourceful guidance. Hope this might benefit many learners. Keep sharing this gainful articles and continue updating us.
    AWS Training in Chennai
    DevOps Training in Chennai
    CCNA Course in Chennai
    RPA Training in Chennai
    Pyhton Training in Chennai
    R Programming Training in Chennai
    Angularjs Training in Chennai

    ReplyDelete
  15. Outstanding blog thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog.
    R Training Institute in Chennai | R Programming Training in Chennai

    ReplyDelete
  16. Nice Article… I love to read your articles because your writing style is too good, its is very very helpful for all of us and I never get bored while reading your article because, they are becomes a more and more interesting from the starting lines until the end.

    Check out : hadoop training in Chennai
    big data training in chennai
    big data hadoop training in chennai
    big data training and placement in chennai

    ReplyDelete
  17. I get an error when building:

    \main.cpp|38|error: no matching function for call to 'cl::Program::build()'|

    ReplyDelete
  18. I tried out and it seems to work. But it is not faster then calculating with CPU, even with 1000000 additions. What is wrong?

    Rolf

    ReplyDelete
  19. Thanks for this blog. It is more Interesting...
    C++ Techniques

    ReplyDelete
  20. I feel this article have given such a lot of vital info for me. And I am satisfied studying your article. However wanna commentary on few general things, The website style is ideal, the articles are truly nice.
    Interior Designers in Chennai | Interior Decorators in Chennai | Best Interior Designers in Chennai | Home Interior designers in Chennai | Modular Kitchen in Chennai

    ReplyDelete
  21. <a href="https://vidmate.vin/

    ReplyDelete
  22. Hello, thenks for this example. Building success, but when I run this progrum ? I have an incorrect result, like result:
    -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460
    Help please, what the problem?

    ReplyDelete
  23. You have provided a nice article, Thank you very much for this one. And I hope this will be useful for many people. And I am waiting for your next post keep on updating these kinds of knowledgeable things
    Android App Development Course in Chennai
    Android Development Course in Bangalore
    App Development Course in Coimbatore
    Mobile Application Development Course in Coimbatore


    ReplyDelete

  24. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    best microservices online training

    ReplyDelete
  25. Great share. Hands on basic make master in programming. Start with basic to job oriented training in Nagpur.
    -----------------------------------------------
    Webgurukul IT Training & Placement Institute

    ReplyDelete
  26. Hello Admin!

    Thanks for the post. It was very interesting and meaningful. I really appreciate it! Keep updating stuffs like this. If you are looking for the Advertising Agency in Chennai / Printing in Chennai , Visit us now..

    ReplyDelete
  27. i found this article more informative, thanks for sharing this article!
    showbox
    showbox for pc

    ReplyDelete
  28. Great Article. Thank-you for such useful information. I have read many of your post and this post is wonderful....
    http://pihmct.com/
    Best hotel management college
    Top hotel management college
    Best hotel management college near me
    diploma in hotel management
    Best hotel management institute
    Best institute for hotel management
    Get trained by professional and build your career in top Multi-national companies.

    ReplyDelete
  29. Best tutorial blog share.
    Get job based , live project IT course training in Nagpur.
    Search more here: PHP Classes in Nagpur - Web Designing Classes in Nagpur

    ReplyDelete
  30. I find this blog to be very interesting and very resourceful. I would say that your blogs are really interesting and informative for me and this article explained everything in detail.
    Best pathology in lucknow
    Best pathology in jankipuram
    Diagnostic centre in lucknow
    X-ray pathology in jankipuram
    Best diagnostic centre in lucknow
    Pathology centre in jankipuram

    ReplyDelete

  31. Great sharing article, I like to visit your website
    free software download

    ReplyDelete
  32. BSc Cardio Vascular Technology is one of the best demanding courses in recent times. Here you can check the all details of this course and the best college to study in Bangalore for this course. Just click the below mentioned link.
    BSc Cardiac Care Technology Colleges In Bangalore

    ReplyDelete
  33. Really nice and interesting post. I was looking for this kind of information and enjoyed reading this one. Keep posting. Thanks for sharing.
    data analytics courses
    data science interview questions

    ReplyDelete
  34. Both are really great. But its purely related to your taste. I prefer pursuing a degree in computer science and start learning digital marketing.
    ExcelR Digital Marketing Courses In Bangalore

    ReplyDelete
  35. I am inspired with your post writing style & how continuously you describe this topic on software testing tutorial . After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic.

    ReplyDelete
  36. This is a wonderful article, Given so much info in it, These type of articles keeps the users interest in the website, and keep on sharing more ... good luck... Thank you!!! digital marketing courses in Bangalore

    ReplyDelete
  37. Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better. The post is written in very a good manner and it contains many useful information for me. Thank you very much and will look for more postings from you.


    digital marketing blog
    digital marketing bloggers
    digital marketing blogs
    digital marketing blogs in india
    digital marketing blog 2020
    digital marketing blog sites
    skartec's digital marketing blog
    skartec's blog
    digital marketing course
    digital marketing course in chennai
    digital marketing training
    skartec digital marketing academy

    ReplyDelete
  38. Thanks for Sharing This Article.It is very so much valuable content. I hope these Commenting lists will help to my website
    servicenow online training
    best servicenow online training
    top servicenow online training

    ReplyDelete
  39. Are you looking for play bazaar were you get the latest satta result.

    ReplyDelete
  40. I can see that you are an expert at your field! I am launching a website soon, and your information will be very useful for me.. Thanks for all your help and wishing you all the success in your business.satta king

    ReplyDelete
  41. With the help of creative designing team TSS advertising company provides different branding and marketing strategies in advertising industry...
    https://www.tss-adv.com/branding-and-marketing

    ReplyDelete
  42. I grow to be greater than satisfied to find this fantastic website on line. I need to to thanks in your time because of this first-rate look at!! I truly cherished each bit of it and I have you ever ever bookmarked to look new facts for yourwebsite.

    ReplyDelete
  43. article from a very amazing blog, Good Job, Thank you for presenting a wide variety of information that is very interesting to see in this artikle
    Home elevators Melbourne
    Home lifts

    ReplyDelete
  44. Awesome blog, I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the
    good work!.data analytics courses

    ReplyDelete
  45. shabe barat
    Shab E Baraat When the 7th month of the

    Islamic calendar Rajab ends, the 8th month of the lunar calendar begins, this month is referred to as Shabaan.

    The importance, it is believed, lies with the 15th night of this month. shab e barat ki nafil namaz in

    hindi
    shab e barat ki namaz,

    shab e barat namaz, shab e barat namaz niyat, shab e barat namaz rakats, shab e barat quotes,
    shabe barat ki namaz, shabe barat namaz, shab e barat 2020shab e barat in india
    shab e barat dua, shab e barat nafil namaj


    --------------------------------------------------------------------

    Ramadan Kareem

    Wishes, Quotes, Greetings
     ? Then, this collection of Ramadan wishes and Ramadan Mubarak

    messages is for you. Here, you’ll find inspirational Ramadan Mubarak greetings that are hoping your

    recipient to have a blessed celebration of Ramadan. happy ramadan, happy ramadan wishes, happy ramzan,
    ramadan greetings, ramadan greetings in English, ramadankareem quotes, ramadan kareem wishes, ramadan wishes, ramzan quotes, ramzan. Ramadan calendar 2020, ramadan 2020 calendar, Ramadan mubarak 2020

    Thanks all

    ReplyDelete
  46. Kudos for delivering such an informative post. Have understood a lot from this concept. Gonna follow your updates from now on.

    Machine Learning Training In Hyderabad

    ReplyDelete
  47. Thanks for giving great kind of information. So useful and practical for me. Thanks for your excellent blog, nice work keep it up thanks for sharing the knowledge. | Home lifts

    ReplyDelete
  48. Great post i must say and thanks for the information. Education is definitely a sticky subject. However, is still among the leading topics of our time. I appreciate your post and look forward to more.
    data analytics courses in mumbai

    ReplyDelete
  49. Thanks for sharing this informatiions.
    artificial intelligence training in coimbatore

    Blue prism training in coimbatore

    RPA Course in coimbatore

    C and C++ training in coimbatore

    big data training in coimbatore

    hadoop training in coimbatore

    aws training in coimbatore

    ReplyDelete
  50. thanks for sharing nice information. its Very use full and informative and keep sharing.
    more : https://www.analyticspath.com/machine-learning-training-in-hyderabad

    ReplyDelete
  51. Amazing post, Thank you for presenting a wide variety of information that is very interesting to see in this article. Visit our website
    Home elevators UAE
    Home elevators Malaysia
    Home lifts Melbourne
    Home lifts

    ReplyDelete
  52. The basic intention behind playing Satta is to become rich within a short span and efforts. Well! It is a wonderful idea and highly appreciated as above 90% of participants get success in their first attempt only. However, play this lottery or game online or offline in an accurate way is a significant factor to win this game. Thus, you have to learn the rules and regulations associated with playing this game in a tactful manner. Briefly, you have to learn those skills and tactics that will make you win in this game.. Read more- Satta bazar

    ReplyDelete
  53. I was just browsing through the internet looking for some information and came across your blog. I am impressed by the information that you have on this blog. It shows how well you understand this subject. Bookmarked this page, will come back for more....bangalore digital marketing course

    ReplyDelete
  54. I was just browsing through the internet looking for some information and came across your blog. I am impressed by the information that you have on this blog. It shows how well you understand this subject. Bookmarked this page, will come back for more....data science courses

    ReplyDelete
  55. Education is definitely a sticky subject. it is still among the leading topics of our time Seo company london.

    ReplyDelete
  56. Awesome blog. I enjoyed reading your articles. This is truly a great read for me. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work!
    Data Science Training in Bangalore

    ReplyDelete
  57. Forex Signals, MT4 and MT5 Indicators, Strategies, Expert Advisors, Forex News, Technical Analysis and Trade Updates in the FOREX IN WORLD

    Forex Signals Forex Strategies Forex Indicators Forex News Forex World

    ReplyDelete
  58. Fantastic blog extremely good well enjoyed with the incredible informative content which surely activates the learners to gain the enough knowledge. Which in turn makes the readers to explore themselves and involve deeply in to the subject. Wish you to dispatch the similar content successively in future as well.

    360DigiTMG Digital Marketing Course

    ReplyDelete
  59. Thanks For Sharing The Information The Information Shared Is Very Valuable Please Keep Updating Us
    By Cognex
    AWS Training in Chennai

    ReplyDelete
  60. This comment has been removed by the author.

    ReplyDelete
  61. This blog is the general information for the feature. You got a good work for these blog.We have a developing our creative content of this mind.Thank you for this blog. This for very interesting and useful.

    Digital Marketing Training in Chennai
    Digital Marketing Training in Bangalore
    Digital Marketing Training in Delhi
    Digital Marketing Online Training

    ReplyDelete

  62. Fantastic informative article! I'm basically getting willing to over this advice, is quite beneficial my own friend.

    Cyber Security Course In Bangalore

    ReplyDelete
  63. Hey, Nice one information

    Online IT Software Courses Training ICT South Bopal - Ahmedabad, India

    Institute of Computer Training - ICT Bopal

    ReplyDelete
  64. I want to say thanks to you. I have bookmark your site for future updates. Oregon Business Registryv

    ReplyDelete
  65. Nice post!

    Worried About QuickBooks Error ?Get in touch with QuickBooks expert for instant solution.
    Click Here to know how to fix QuickBooks Error 8007

    Dial on QuickBooks Error Phone Number +1-855-977-7463.

    ReplyDelete
  66. Hi there, I found your blog via Google while searching for such kinda informative post and your post looks very interesting for me
    Digital Marketing Training Institutes in Hyderabad

    ReplyDelete
  67. Very educating story, saved your site for hopes to read more! ExcelR Data Analytics Courses

    ReplyDelete
  68. Thanks for your marvelous posting! I really enjoyed reading it, you happen to be a great author. I will remember to bookmark your blog and may come back in the foreseeable future.
    I want to encourage that you continue your great writing, have a nice evening!

    Read More:-

    Satta King

    ReplyDelete
  69. Samsung mobile phone is a very popular mobile company not only in Bangladesh but also all over the world. But its price is so high. When you are searching for a brand new mobile phone & it becomes hard. Then you can find a Samsung second hand mobile price in bangladesh for your urgency.

    ReplyDelete
  70. This is the correct site for every individual who might want to get some answers concerning this point. You understand such a lot of its practically intense to contend with you (not that I really would need to… HaHa).live You certainly put a new turn on a theme which has been talked about for a very long time. Awesome stuff, simply extraordinary!

    ReplyDelete
  71. Nice Blog !
    QuickBooks Error 248 can occur when a user tries to run payroll for the employees. You may also encounter this issue when you are taking a backup of your company file.call us and get the best possible solutions to resolve QuickBooks Error 248.

    ReplyDelete

  72. I see some amazingly important and kept up to length of your strength searching for in your on the site
    Digital Marketing Training Institutes in Hyderabad

    ReplyDelete
  73. Your blog is very nice and has sets of the fantastic piece of information. Thanks for sharing with us. If you face any technical issue or error, visit:

    Quickbooks customer service

    ReplyDelete
  74. Thanks for this wonderful content, I really appreciate the same.

    If you are looking for best water and amusement park located in the heart of beautiful City- Lucknow,then visit
    Best Water Park in Lucknow
    Best water park in Uttar Pradesh
    Best hotel for destination wedding in Lucknow

    ReplyDelete
  75. Informative blog
    https://360digitmg.com/india/data-science-using-python-and-r-programming-in-patna

    ReplyDelete
  76. Very informative blog and valuable article thanks for sharing with us, keep posting more and share about aws.

    by cognexAWS Training in chennai

    ReplyDelete
  77. Very Good Article Get instant & Latest Updated Satta King result of Satta King Gali Result Faridabad Result Ghaziabad Result, Desawar Result , Panihari satta result, aghori satta Result And Many More Result Go Through bhutni Satta King .We are Provide fast And 100% Accurate Results.

    ReplyDelete
  78. I read this blog post and this blog post is one of the best blog post, so keep more post for sharing. Primavera Course in Chennai | primavera online training

    ReplyDelete
  79. This post is really nice and informative. The explanation given is really comprehensive and informative.
    IOS Training
    Web Designing course in Chennai
    Salesforce CRM Training in Chennai
    Salesforce CRM Training

    ReplyDelete
  80. I was very pleased to find this site.I wanted to thank you for this great read!! I definitely enjoy every little bit of it and I have you bookmarked to check out new stuff you post.
    business analytics course

    ReplyDelete
  81. Very good info. Lucky me I discovered your site by chance (stumbleupon). I have saved it for later! Here is my web site:sattaking

    ReplyDelete
  82. Digital Marketing, Digital Marketing Online Training, Digital Marketing Training Programs, Women Entrepreneurship, Women Entrepreneurship Training Programs, Digital marketing online video course, Women Entrepreneurship Online Certification Course, Business coaching, Training for Business owners, Business coaching for women, young entrepreneurs training

    https://www.eminentdigitalacademy.com/

    ReplyDelete

  83. This is, in my opinion, one of the most crucial pieces of information. And I'm delighted I'm enjoying reading your content.

    digital marketing training in hyderabad
    digital marketing course in ameerpet
    digital marketing course training in hyderabad ameerpet

    ReplyDelete
  84. Writing in style and getting good compliments on the article is hard enough, to be honest, but you did it so calmly and with such a great feeling and got the job done. This item is owned with style and I give it a nice compliment. Better!

    Best Data Science Courses in Bangalore

    ReplyDelete
  85. Hey! Lovely blog. Your blog contains all the details and information related to the topic. In case you are a QuickBooks user, here is good news for you. You may encounter any error like QuickBooks Error, visit at QuickBooks Customer Service Phone Number for quick help.

    ReplyDelete
  86. We are really grateful for your blog post. You will find a lot of approaches after visiting your post. Great work
    data science training

    ReplyDelete
  87. Thanks for posting! I really like what you've acquired here; You should keep it up forever!Private tutor Georgetown Best of luck

    ReplyDelete
  88. Thanks for this post...This Best C++ CourseBest C++ course is one of the most comprehensive and detailed courses on C++ for beginners. It puts learners on a fast track to success by helping them master Modern C++ programming skills within a short time. The course format includes theory and concepts which are then reinforced with live code examples.
    Best Training Institute in Dubai
    Adobe Illustrator Course
    Premiere Editing Course

    ReplyDelete
  89. Excellent Blog to read. You have shared useful information. Thank you.
    Best SEO Course Online
    SEO Certification Course

    ReplyDelete
  90. Thanks for posting! I really like what you've acquired here; You should keep it up forever!Private Tutor Pensacola Best of luck

    ReplyDelete
  91. Thanks for posting! I really like what you've acquired here; You should keep it up forever!Private Tutor WELLESLEY Best of luck

    ReplyDelete
  92. Really thanks for sharing such an useful & informative stuff...

    Best MicroNutrients Company in India

    ReplyDelete
  93. I used to be able to find good information from your blog posts.The Satta King is the satta king result provider website, Which provide the satta king fast result in Ghaziabad Satta King, Faridabad Satta King, Delhi satta king, Desawar Gali result and many more.

    Best Satta King Result Site: Satta King

    ReplyDelete
  94. This Digital Marketing Course in Mohali transforms you into a complete Digital Marketer with expertise in modules like SEO, Social Media Marketing, PPC, Analytics, Content, Mobile, and Email marketing.
    We provide the Best training for Social Media Marketing and PPC course in Mohali and have trained over 10k students.
    Become industry-ready learning the latest tools, working on real-world projects, and attending Master classes from the Google and Facebook certified Team.
    Digital Marketing Course in Chandigarh

    ReplyDelete
  95. Thanks again for the blog article.Really thank you! Want more.
    satta leak number free

    ReplyDelete
  96. I really want to appreciate the way to write this article. It seems that you are very professional and intelligent on the above topics of writing. I enjoyed reading your article very much.

    satta leak number free

    ReplyDelete
  97. Thank you so much for your post. Really amazing post.satta king

    ReplyDelete
  98. Really good info I always like to read and spread such information which is unique and in fact informative. Keep up the good work.
    satta king

    ReplyDelete
  99. Good job, this is really useful topic for me.
    satta king

    ReplyDelete
  100. Wonderful illustrated information. I thank you for that. No doubt it will be very useful for my future projects. Would like to see some other posts on the same subject!
    data science classes in hyderabad

    ReplyDelete
  101. I cannot thank you enough for the blog.Thanks Again. Keep writing.
    net coure
    net training

    ReplyDelete
  102. Thanks for sharing amazing information keep posting!
    mangaowl

    ReplyDelete
  103. Nice blog. Informative and knowledgeable content. Big thumbs up for this blog. I really enjoyed this blog. Thank you for sharing with us.
    Data Science Training in Hyderabad

    ReplyDelete
  104. Interesting... i think i would bookmark this site. m bout to get busy now but hey! ill come back later

    ReplyDelete