I'm absolutely new to OpenCL programming. I have a working installation of OpenCL library and drivers. But the program I'm trying to run is not producing expected output (Output is all zeros). It is just a simple vector_add program.
Thanks in advance for suggestions.
int main(int argc, char** argv)
{
cout << "Hello OpenCL" << endl;
vector<Platform> all_platforms;
int err = Platform::get(&all_platforms);
cout << "Getting Platform ... Error code " << err << endl;
if (all_platforms.size()==0)
(cout << "No platforms" << endl, exit(0));
cout << "Platform info : " << all_platforms[0].getInfo<CL_PLATFORM_NAME>() << endl;
Platform default_platform = all_platforms[0];
cout << "Defaulting to it ..." << endl;
vector<Device> all_devices;
err = default_platform.getDevices(CL_DEVICE_TYPE_GPU, &all_devices);
cout << "Getting devices ... Error code : " << err << endl;
if (all_devices.size()==0)
(cout << "No devices" << endl, exit(0));
Device default_device = all_devices[0];
cout << all_devices.size() << " devices & " << "Device info : " << all_devices[0].getInfo<CL_DEVICE_NAME>() << endl;
cout << "Defaulting to it ..." << endl;
Context context(default_device);
Program::Sources sources;
std::string kernel_code=
" void kernel simple_add(global const int* A, global const int* B, global int* C){"
" unsigned int i = get_global_id(0); "
" C[i]=A[i]+B[i]; "
" } ";
sources.push_back(make_pair(kernel_code.c_str(), kernel_code.length()+1));
Program program(context, sources);
if (program.build(all_devices)==CL_SUCCESS)
cout << "Built Successfully" << endl;
Buffer buffer_A(context,CL_MEM_READ_WRITE,sizeof(int)*10);
Buffer buffer_B(context,CL_MEM_READ_WRITE,sizeof(int)*10);
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};
CommandQueue queue(context,default_device);
queue.enqueueWriteBuffer(buffer_A,CL_TRUE,0,sizeof(int)*10,A); // load data from host to device
queue.enqueueWriteBuffer(buffer_B,CL_TRUE,0,sizeof(int)*10,B);
Kernel kernel(program, "vector_add");
kernel.setArg(0, buffer_A);
kernel.setArg(1, buffer_B);
kernel.setArg(2, buffer_C);
queue.enqueueNDRangeKernel(kernel,cl::NullRange,cl::NDRange(10),cl::NullRange);
queue.finish();
int *C = new int[10];
queue.enqueueReadBuffer(buffer_C, CL_TRUE, 0, 10 * sizeof(int), C);
for (int i=0;i<10;i++)
std::cout << A[i] << " + " << B[i] << " = " << C[i] << std::endl;
return 0;
}
As pointed out in the comments, you should always check the error codes when using OpenCL API functions. This can be achieved by enabling exception handling in the C++ wrapper:
#define __CL_ENABLE_EXCEPTIONS // with cl.hpp
//#define CL_HPP_ENABLE_EXCEPTIONS // with cl2.hpp
#include <CL/cl.hpp>
int main(int argc, char *argv[])
{
try
{
// OpenCL code here
}
catch (cl::Error& err)
{
cout << err.what() << " failed with error code " << err.err() << endl;
}
}
If you do this, you will receive useful information about a couple of issues with your code.
The clCreateKernel function returns CL_INVALID_NAME. In your kernel, you define the kernel function with the name simple_add, but then you try and create a kernel object using the name vector_add.
If you have an OpenCL platform with multiple devices, you may also receive an error when building your kernel program. This is because you are creating an OpenCL context with a single device, but then trying to build the program for a list of devices:
Context context(default_device);
// ...
if (program.build(all_devices)==CL_SUCCESS)
cout << "Built Successfully" << endl;
The simplest fix is just to remove the argument from the build function, since by default it will build the program for all devices in the context (which is almost always what you actually want):
if (program.build()==CL_SUCCESS)
cout << "Built Successfully" << endl;
Related
Can I use twincat-ads to query a Beckhoff PLC for the variables (and their types) that are exposed on ADS.
Yes you can.
This example comes directly from the Beckhoff ads documentation which you should study a bit in order to understand the basics of the ads protocol.
/// <summary>
/// Defines the entry point of the application.
/// </summary>
/// <param name="args">The arguments.</param>
static void Main(string[] args)
{
Console.WriteLine("");
Console.WriteLine("Press [Enter] for start:");
Console.ReadLine();
// Parse the command-line arguments
AmsAddress address = ArgParser.Parse(args);
using (TcAdsClient client = new TcAdsClient())
{
// Connect the AdsClient to the device target.
client.Connect(address);
// Load symbolic information
ISymbolLoader loader = SymbolLoaderFactory.Create(client, SymbolLoaderSettings.Default);
ReadOnlySymbolCollection allSymbols = loader.Symbols;
ISymbol bVar1 = allSymbols["GVL.bVar1"];
ISymbol bVar2 = allSymbols["GVL.iCount"];
ISymbol projectName = allSymbols["TwinCAT_SystemInfoVarList._AppInfo.ProjectName"];
SymbolCollection symbols = new SymbolCollection() {bVar1, bVar2, projectName};
// Sum Command Read
SumSymbolRead readCommand = new SumSymbolRead(client,symbols);
object[] values = readCommand.Read();
for (int i = 0; i < symbols.Count; i++)
{
Console.WriteLine("Symbol: {0} (Value: {1}, Type: {2})",symbols[i].InstancePath,values[i].ToString(),values[i].GetType().Name);
}
// Sum Command Write
SumSymbolWrite writeCommand = new SumSymbolWrite(client,symbols);
object[] writeValues = new object[] {true, (short) 42, "MyNewProjectName"};
writeCommand.Write(writeValues);
}
Console.WriteLine("");
Console.WriteLine("Press [Enter] for leave:");
Console.ReadLine();
}
In C++ you need to use the AdsSyncReadReq function:
#include <iostream.h>
#include <windows.h>
#include <conio.h>
#include <assert.h>
// ADS headers for TwinCAT 3
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsAPI.h"
void main()
{
long nErr, nPort;
char *pchSymbols = NULL;
UINT uiIndex;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
AdsSymbolUploadInfo tAdsSymbolUploadInfo;
PAdsSymbolEntry pAdsSymbolEntry;
// Open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
// Select Port: TwinCAT 3 PLC1 = 851
pAddr->port = 851;
// Read the length of the variable declaration
nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOADINFO, 0x0, sizeof(tAdsSymbolUploadInfo), &tAdsSymbolUploadInfo);
if (nErr) cerr << "Error: AdsSyncReadReq: " << nErr << '\n';
pchSymbols = new char[tAdsSymbolUploadInfo.nSymSize];
assert(pchSymbols);
// Read information about the PLC variables
nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOAD, 0, tAdsSymbolUploadInfo.nSymSize, pchSymbols);
if (nErr) cerr << "Error: AdsSyncReadReq: " << nErr << '\n';
// Output information about the PLC variables
pAdsSymbolEntry = (PAdsSymbolEntry)pchSymbols;
for (uiIndex = 0; uiIndex < tAdsSymbolUploadInfo.nSymbols; uiIndex++)
{
cout << PADSSYMBOLNAME(pAdsSymbolEntry) << "\t\t"
<< pAdsSymbolEntry->iGroup << '\t'
<< pAdsSymbolEntry->iOffs << '\t'
<< pAdsSymbolEntry->size << '\t'
<< PADSSYMBOLTYPE(pAdsSymbolEntry) << '\t'
<< PADSSYMBOLCOMMENT(pAdsSymbolEntry) << '\n';
pAdsSymbolEntry = PADSNEXTSYMBOLENTRY(pAdsSymbolEntry); cout.flush();
}
getch();
// Close communication port
nErr = AdsPortClose();
if (nErr) cerr << "Fehler: AdsPortClose: " << nErr << '\n';
// Release memory
if (pchSymbols) delete(pchSymbols);
}
For more info:
https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_ads_intro/9007199370899851.html&id=5869483416056481636
I got this code from a book. When I ran on Visual Studio, it said to switch strcpy() to strcpy_s(), and after I did that, it seems the program terminated at the delete pointer. I tried to run on Dev-C++, and it works fine. Anyone knows why? Thank you.
#include "pch.h"
#include <iostream>
#include <cstring>
int main()
{
cout << "Enter a kind of animal: ";
cin >> animal; // ok if input < 20 chars
ps = animal; // set ps to point to string
cout << ps << "!\n"; // ok, same as using animal
cout << "Before using strcpy():\n";
cout << animal << " at " << (int *)animal << endl;
cout << ps << " at " << (int *)ps << endl;
ps = new char[strlen(animal) + 1]; // get new storage
strcpy_s(ps, sizeof(animal), animal); // copy string to new storage
cout << "After using strcpy():\n";
cout << animal << " at " << (int *)animal << endl;
cout << ps << " at " << (int *)ps << endl;
delete[] ps;
return 0;
}
I'm using opencv in a Qt app. I've seen some generic c++ ways of printing out the values of a Mat and have done so with
cout << "myMat = "<< endl << " " << myMat << endl << endl;
Ideally I could have a QString with the contents of this Mat. Is there a neat way to do this?
You can use ostringstream and its method str() to get string which you can pass as parameter to QString constructor.
cv::Mat M(2,2, CV_8UC3, cv::Scalar(0,0,255));
ostringstream oss;
oss << "M = " << endl << " " << M << endl;
QString matContent(oss.str()); // QT3
QString matContent2(oss.str().c_str()); // QT4/5 (const char*) constructor
I am trying to pass a random number generator around my program (I want to use a single one), however I cannot seem to find a way to pass it by reference.
Here is what I have tried thus far:
#include <iostream>
#include <random>
#include <functional>
using namespace std;
void test(const function<int()> arng0, const function<int()> & arng1, const function<int()> & arng2,
const function<int()> frng0, const function<int()> & frng1, const function<int()> & frng2)
{
cerr << "Auto - std::_bind size: " << sizeof(arng0) << endl;
cerr << "Auto - std::_bind & size: " << sizeof(arng1) << endl;
cerr << "Auto - std::_bind ref size: " << sizeof(arng2) << endl;
cerr << "Functional size: " << sizeof(frng0) << endl;
cerr << "Functional & size: " << sizeof(frng1) << endl;
cerr << "Functional ref size: " << sizeof(frng2) << endl;
}
void main()
{
default_random_engine e;
uniform_int_distribution<int> dist(0, 100);
auto autoRng = bind(ref(dist), ref(e));
function<int()> funcRng = bind(ref(dist), ref(e));
test(autoRng, autoRng, ref(autoRng),
funcRng, funcRng, ref(funcRng));
system("Pause");
}
The output is 24 bytes for all of them. I know functional is a heavy wrapper, however passing by reference still should be 4 bytes?
Answer:
void testValue(const function<int()> arng0)
{
arng0();
}
void testRef(const function<int()> & arng0)
{
arng0();
}
{// Pass by value
auto start = high_resolution_clock::now();
for (unsigned int i = 0; i < 100000; i++)
{
testValue(funcRng);
}
auto end = high_resolution_clock::now();
auto total = duration_cast<milliseconds>(end - start).count();
cerr << "TestVal time: " << total << endl;
}
{// Pass by ref
auto start = high_resolution_clock::now();
for (unsigned int i = 0; i < 100000; i++)
{
testRef(funcRng);
}
auto end = high_resolution_clock::now();
auto total = duration_cast<milliseconds>(end - start).count();
cerr << "TestRef time: " << total << endl;
}
Results:
Test Value Time: 179 ms
Test Ref Time: 74 ms
I think you've got it right, passing by reference should be 4 bytes if you're on a 32 bit machine. sizeof is giving you the size of the thing being referenced, not the size of the reference. I don't think you need to use 'ref' at the callsite.
See sizeof documentation here:
http://en.cppreference.com/w/cpp/language/sizeof
//#include <QtCore/QCoreApplication>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include "shift.h"
using namespace::std;
int main(int argc, char *argv[])
{
unsigned char tmpBuf;
FILE* fp;
FILE* fp2;
char fname[50];
static unsigned int lSize, count, num;
cout << "Input the filename:" << endl;
cin >> fname;
fp = fopen(fname,"r");
if(fp == NULL) {
cout << "The file does not exist!" << endl;
exit(1);
}
// obtain file size:
fseek(fp , 0 , SEEK_END);
lSize = ftell(fp);
rewind(fp);
cout << "The intput file's size is: " << lSize << endl;
fp2 = fopen("myfile", "w");
while(1){
num = fread(&tmpBuf, 1, 1, fp);
count += num;
// putchar(tmpBuf);
// tmpBuf = cror(tmpBuf, 4);
// tmpBuf = crol(tmpBuf, 4);
fwrite(&tmpBuf, 1, num, fp2);
cout << tmpBuf << " " << num << " " << count << endl;
if (count == lSize){
printf("over\n");
break;
}
}
fclose(fp);
fclose(fp2);
while(1){}
return 0;
//return a.exec();
}
I made a Qt console program and disable QtCore, like above code. When read some file, e.g. 1.txt (which contains only 1234567890) it succeeds. But when reading some other file, e.g. 1.rar, it failed like below: Why?
Check the value of num coming back from
num = fread(&tmpBuf, 1, 1, fp);
If it comes back as 0, that would explain why
if (count == lSize){
never comes back as true to break you out of the loop.
As to why that could happen, you're opening fname in "r" mode but a rar file would be binary. For that, I'd suggest opening in "rb" mode. If fread expects txt format but hits the EOF indicator, it'll stop advancing so num = 0 and count won't increase.
I don't have windows available to test this, but other questions have come up on stackoverflow for this reason:
fread/ftell apparently broken under Windows, works fine under Linux