Embedded2014. 8. 1. 01:12

금번에 개발한 안드로이드 기반의 Digital Shelf 입니다.


WiFi

NFC

Multimedia player 등등 


LCD 3개를 동시에 구동할 수 있도록 구성하였습니다.


관련된 세부 사항은 이곳에 있습니다.



'Embedded' 카테고리의 다른 글

Air Play & MiraCast & MirrorLink  (0) 2014.09.22
차량용 안드로이드 셋탑 박스  (0) 2014.08.12
Embedded 4K Board::Quad  (1) 2014.07.05
철도/버스용 PIS 시스템  (0) 2014.04.08
더욱 작게 만든 i.MX6 board  (0) 2014.01.25
Posted by GUNDAM_IM
Books2014. 7. 26. 14:14




[도서] 프로그래머, 수학으로 생각하라 : 논리적인 생각과 문제 해결에 필요한 아이디어를 얻는 수학 읽기 
유키 히로시 저/안동현 역 | 프리렉(이한디지털리) | 2014년 02월 


수학좋아하고 프로그래밍 하는것을 좋아하면 쉽게 쉽게 읽혀지는 책

책의 느낌은 대학교 강의 교재 느낌임.

대학생 느낌으로 읽으면 재미있다.


하지만, 책이 얇아서 읽었지 두꺼웠으면 읽다가 포기했을 책




'Books' 카테고리의 다른 글

페르시아의 왕자  (0) 2014.08.10
최진기의 끝내주는 전쟁사 특강 1  (0) 2014.08.03
지금 경계선에서  (0) 2014.07.20
작은 회사 사장의 전략  (0) 2014.04.24
미친듯이 심플 : 스티브 잡스, 불멸의 경영 무기  (0) 2014.04.22
Posted by GUNDAM_IM
Books2014. 7. 20. 19:30





레베카 코스타 지음
역자
장세현 옮김 역자평점 8.6
출판사
쌤앤파커스 | 2011.02.01







문명이 흥하고 망하는 이유는 사회와 현상의 복잡성이 증가하는 속도에 비해서 그 복잡성을 인식해야하는 사람의 능력이 따라가지 못하여서 이다. 


-  로마의 부흥과 멸망
-  마야의 부흥과 멸망
- 캄보디아의 크르메제국

오래된 문명이 동서양 심지어 남 아메리카에서 비슷한 시점에 흥하고 망하여 갔는데
그 흥망의 패턴이 놀랍도록 유사하다 

이 흥망의 패턴은
- 현상을 합리적이고 통제 가능한 방식으로 이해하면서 문명은 흥하기 시작하고
- 복잡성의 증가로 인식 불가능한 상황으로 도달해 갈때 문명은 망하고 사라진다
라는 패턴으로 반복된다.

이렇게 하나의 문명조차 좌우 할 수 있는 패턴,  즉 복잡성의 증가와 인식 능력의 느린 진화는 복잡성을 미신이나 잘못된 방향으로 인식하게 된다.  이것을 슈퍼 밈이라고 부른다. 

이러한 슈퍼 밈은 

- 불합리한 반대
   사회에 무엇이든 반대하는 분위기가 팽배하면 그 사회는 무엇인가에 조정당할 가능성이 극히 높아진다.

- 책임의 개인화
   복잡성에 지배당하게 되면 차라리 이해하게 쉬운 더 간단한 이유 즉 개인에게 책임을 묻기 시작한다.

- 거짓 상관관계
  인과 간계와 상관관계가 틀린데 그것을 동일시하여 문제의 본질을 호도하게 된다 

- 사일로식 사고
  구획화된 사고는 상호간 권한과 자금 자원을 얻기위한 다툼에 들어가게,한다

- 극단의 경제학
   모든 부분을 경제논리가 접수했다. 하지만 경제 논리로 풀지 못하는 문제가 더 많다. 

으로 표현된다. 

이러한 슈퍼밈은 고대에는 가뭄을 막기위해 신에게 바쳐지는 처녀의 피처럼 복잡한 현상을 (그 당시에는) 가장 이해하기 쉽고 통제하기 쉬운 방향으로 인식 부조화를 해결해 나가는 것이다.  

이러한 인식 능력과 복잡성 증가의 부조화를 해결하기 위해서는 통찰이란 능력을 개발해야 한다고 책에서는 주장한다.  유레카의 순간이라는 이 통찰의 순간을 통해서 인간은 진화를 앞당기고 현상을 이해하는 능력을 향상시킨다. 


이 책은 그동안 생각 못했던 문명의 흥망을 복잡성의 증가와 인식 능력의 느린 발달의 부조화라는 관점에서 설명하였다.  그리고 그 해결책을 통찰을 키우고 통찰 능력을 높이기 위한 훈련을 제시한다. 




P92 지금도 인간은 본질적으로 예전과 같은 생물학적 한계에 갇혀서 원시적이고 예측 가능한 방식으로 정보에 대응하거나 데이터를 처리한다. 

P102 지식 습득 능력이 감퇴하는 만큼 믿음에 대한 취약성은 높아진다. 뇌의 생물학적 능력을 넘어서는 복잡성에 직면했을때, 우리는 입증되지 않은 이데올로기를 쉽게 받아들이고 위험한  "군중 심리"에 순순히 따르게 되는 것이다 

P107 다양성이 커질 수록 복잡성이 증가한다. 

P115 슈퍼밈은 "인식 한계점"에 도달한 결과 등장한다. 

P119- 144. 문제의 제기와 반대는 누구나 하지만 해결책은 아무도 내놓지 않는다 

P135 통찰은 어느것이 최선인가 라는 사고를 거부하고 무엇이 최선인가를 사고를 선호한다.  

P186 인과 관계를 입증하는데 필요한 기준이 위험할 정도로 느슨한 시대가 되었다

P207 하나의 관점만 옳고 다른 것은 틀렸다는 의미가 아니다. 다만 더 큰 맥락을 더 광대한 시스템에서 어떻게 여러 관점이 함께 작용하는지 우리가 발견하지 못한 것 뿐이다. 

P219 복잡한 사회 환경에서 사일로식 사고는 영역을 지켜서 생존 기회를 늘리려는 불합리한 본능에 지나지 않을지도 모른다. 

P288 나는 깨어있는 자요

P287-321

- 문명의 패턴을 깨달아라
- 장 단기 전략을 함께 가지고 가라
- 완화책이라는 수렁에 빠지지 마라
- 필요하면 모든 완화책을 다 동원하는 병행적 점진주의를 실행하라
- 지식과 믿음 사이의 균형

결국은 진화다. 


P361- 통찰은 인간의 무기




Posted by GUNDAM_IM
Embedded2014. 7. 5. 10:26


금번에 개발된  4K Display Board 입니다.

UltraHD용 보드이고 출력을 연결하면 VideoWall등에도 사용할 수 있습니다.


Host O/S로는 Android 4,4 Kitkat을 올렸습니다.

세부 자료는 이 페이지에서 참조.....








그동안 틈틈히 연습했던 3D Modeling도 이럴때 써먹는군요...

그냥 패널에 텍스쳐 입히는 정도인데 이런 느낌으로... 



'Embedded' 카테고리의 다른 글

차량용 안드로이드 셋탑 박스  (0) 2014.08.12
Digital Shelf - TRICERA  (0) 2014.08.01
철도/버스용 PIS 시스템  (0) 2014.04.08
더욱 작게 만든 i.MX6 board  (0) 2014.01.25
Embedded Network Switch Board  (0) 2014.01.02
Posted by GUNDAM_IM
Hobby2014. 6. 7. 20:08


요새 뒹국을 왔다갔다 해선가 갑자기 천장지구를 다시 보고 싶어졌다.

유덕화의 비장미 있는 연기와
오천련의 청순 가련형 분위기를 한껏 살려주는  정말 한시대를 풍미했던 영화 천장지구....

                                                                 전성기 시절의 오천련

지금이야 두분다 많이 나이 드셔서 이런 류의 영화에는 출연하지 않고,
비장미 넘치는 홍콩 느와르가 시장에서 거의 사라진 것 처럼 아쉽기만 하다.

주제가인 천약유정(天若有情 )은  테입에 녹음해서 듣고 다니던 시절이 있었다.
그리고 지금도 아이폰에 들어가 있어서 가끔 듣고 다닌다.

홍콩/중국 영화에서는 당연히 여러 느와르 영화가 있고 여러명의 유명 배우가 있지만,
그중에서도 좋아하는 배우를 꼽는다면 개인적으로는 이수현이었다.

순위에 당연히 나오는 주윤발, 유덕화, 장국영을 뺀다면,  

"이 수현"을 제일 좋아했다. 

왼쪽에서 폼 잡고 총쏘시는 분이시다.
첩혈 쌍웅에서 나온 또하나의 주인공이고 몇몇 홍콩 영화에서 경찰 역활 전문으로 했던 인물인데
영화를 많이 안찍고 사라져서 많이 아쉬워 했었었다...... 

첩혈쌍웅은 쌈마이들만이 이해할  수 있는 영화였다.
영웅본색도 멋지지만, 비둘기 날리며, 펼쳐지는 교회의 총격씬은 영웅본색을 무색하게 만들었다. 
나중에 첩혈쌍웅을 모티브로해서  FaceOff라는 미국 영화로 리메이크 형태로 만들어지기도 했었다.


주) 중국분들과 노래방 가게 되는데 그때 써먹을 수 있는 노래가
      이 천약유정 주제가와, 첨밀밀이다. 이거 요긴하다.
      
주) 그때 배웠던 몇몇 단어들을 요새 조금씩 써먹고 다니면,  역시 뭐든지 배워두고 외워두면 언젠간 쓸모가 있는것 같다.
      "따거~~"  : 큰형님 - 가끔 친한 중국 분들에게 해드리면 좋아한다.
      
주) 영화 이야기하면서 점심 내내 때운적있는데
     배우들의 이름을 이야기하고 싶어도 한글 이름과 중국어 발음이 완전히 틀려서 헤메게 된다. 
     미리미리 배우들 중국 식 발음을 암기하고 들어가면 써 먹을 수 있다.
     
      주윤발 :  쭈(어)륜파
      장국영 :  장궈룽
      성용     :  그냥 재키 챈으로 OK
      이소룡 : 당근 블루스 리
      정소추 :  Adam Cheng 

사족으로 정소추는 사극에서 초류향으로 엄청 유명한 인물이다.



                     초류향의 현실 속 재림이라 불린 인물 
                     무협 매니아분 들에겐 유명한 인물이다.   이분이 나온 무협물은 많이 보았던것 같다. 
                     나중에 곽부성이 초류향을 리메이크했었는데,  허접때기 곽부성이 초류향을 한것은 정말 대역죄였다.

                     -> 중국 식 발음은 찾지 못했다. 쩝...
                          당연히 중화권 사람들한테 아담 청 하면 다 아는 유명한 인물이다.


  
      
  



 


'Hobby' 카테고리의 다른 글

칠흑의 미라쥬 머신  (0) 2014.12.16
모노레일 사진  (0) 2014.12.10
오다이바 건담  (0) 2014.03.22
PTOLEMY II를 아시나요 ?  (0) 2014.02.02
FSS. I.M.S. LED Mirage V3  (0) 2013.12.21
Posted by GUNDAM_IM
Computer Vision2014. 6. 1. 06:41

1차원 데이터 열에 대한 커널의 실행은


clEnqueueTask

2혹은 3차원 데이터에 대한 커널의 실행은

clEnqueueNDRangeKernel

에 의해서 실행 된다.

cl_int clEnqueueNDRangeKernel (cl_command_queue command_queue,
 cl_kernel kernel,
 cl_uint work_dim,
 const size_t *global_work_offset,
 const size_t *global_work_size,
 const size_t *local_work_size,
 cl_uint num_events_in_wait_list,
 const cl_event *event_wait_list,
 cl_event *event)


command_queue : 커멘드 큐…
kernel : Kernel
work_dim   : 0 보다는 커야 하지만 3보다는 작거나 같아야 한다.
global work offset : 현재 버전에서는 그냥 0 이 되어야 한다.
global_work_size :  포인터로 정의되고 
                                work_dim의 영향을 받는다. 따라서
                                global_work_size[0] * global_work_size[1] ….  * global_work_size[work_dim-1]
                                이 전체 work_itme의 개수이다.
                                global work_size는 sizeof(size_t)를 초과할 수 없다.
                                무슨 말이냐 하면, 만약 특정 디바이스에서 size를 나타내는 최대 크기가 32이면 
                                즉 2^32이면 이보다는 작아야 한다는 것이다.
                                sizeof(size_t)는 결국 메모리 공간의 포인터의 크기를 의미하는데 32보다 크면 
                               포인터로 지정할 수 있는 공간보다 크다는
                               의미이므로 오류가 되는 것이다.
                                이런 경우에  CL_OUT_OF_RESOURCES   오류가 발생한다.

local_work_size :   work_dim의 배열을 가리키는 unsigned 값이다.
                              work_item 숫자이고 이것은 work-group을 만든다. 그리고 커널이 실행되는 횟수이다.  
                              global_work_size와 마찬가지로
                              local_work_size[0] * local_work_size[1] ….  * local_work_size[work_dim-1] 
                              으로 해서 work_item의 숫자가 결졍된다.  그리고 이 숫자는 
                              CL_DEVICE_MAX_WORK_GROUP_SIZE보다 작아야 한다. 
                              local_work_size[0] <= CL_DEVICE_MAX_WORK_GROUP_SIZE[0]
                              local_work_size[1] <= CL_DEVICE_MAX_WORK_GROUP_SIZE[1]
                                   ….
                              local_work_size[2] <= CL_DEVICE_MAX_WORK_GROUP_SIZE[2]
                    
                              local_work_size는 global_work_item을 workgroup instance로 나누어서 할당하는것을 
                              결정하는데 사용한다.
                              만약 local_work_size가 명시되어 있다면, global_work_size[0] , 
                             global_work_size[1] … global_work_size[work_dim-1]은
                              local_work_size[0] , local_work_size[1] … local_work_size[2]의 값으로 나누어
                              떨어져야 한다.
                                   
                              work-group size는 커널이 프로그램 소스에서  
                              __attribute__((reqd_work_group_size(X,Y,Z))) 에 의해서 사용할 수 있다.
                              이 경우 local_work_size는 이 reqd_work_group_size에 명시된 숫자와 같아야 하낟.

                              귀찮으면 OpenCL이 직접 실행시에 지정할 수 있다. 이럴 경우에 NULL로 명시한다.

(주) global work size는 결국 작업해야 할 전체 work item의 개수를 의미한다.
      이를 local work size로 나누어서 분할하여 작업하게 되는 것이다.
      
각각의 차원을 chunk로 나눌 것이다. 이때 나누어지는 chunk의 개수는 2,3,4….CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 까지 가능하다.
이 값은 아래와 같은 방법으로 확인이 가능하다.

  /* the cl_device_info are preprocessor directives defined in cl.h */
  
switch (param_name) {
        …
    case CL_DEVICE_VENDOR_ID : 
    
case CL_DEVICE_MAX_COMPUTE_UNITS : 
    case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS : {
            cl_uint* ret = (cl_uint*) alloca(
sizeof(cl_uint) * paramSize);
            error = clGetDeviceInfo( id, param_name, paramSize, ret, 
NULL );
            
if (error != CL_SUCCESS ) {
                perror(
"Unable to obtain device info for param\n");
                
return;
            }
            
switch (param_name) {
                
case CL_DEVICE_VENDOR_ID: printf("\tVENDOR ID: 0x%x\n", *ret); break;
                
case CL_DEVICE_MAX_COMPUTE_UNITS: printf("\tMaximum number of parallel compute units: %d\n", *ret); break;
                
case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: 
                                   printf("\tMaximum dimensions for global/local work-item IDs: %d\n", *ret); break;
            }
         }
break;


processing group을 병렬로 실행할 수 있고, 이 것을 work group으로 부른다. work group은 work item이라 부르는 개별적인 병렬 실행 단위를 가진다. 저자는 이 것을 executable thread라고 개념적으로 보고 있다.



위의 예에서 보면 2차원으로 구성된 공간을 9개의 work group으로 나눈다. 각각의  work group은 4x4의 work item으로 구성된다.
work item을 할당하는 데에는 2가지 방법이 있다.
하나의 work item을 하나의 work group에 할당하는 방법과
n x n 개의 work item을 (이 경우 4x4가 된다.) work group에 할당하는 방법이 있다.

우선 첫번째 방식으로 진행한다고 가정하고 진행한다.

…. 코드…

프로그램을 실행시키면 오류가 발생한다.

Number of OpenCL platforms found: 1
Number of detected OpenCL devices: 3
Running on CPU ........
=> Kernel name: copy2Dfloat4 with arity: 2
=> About to create command queue and enqueue this kernel...
Unable to enqueue task to command-queue: No such file or directory 
...

어떤 원인으로 발생된지 모르므로 이를 다시 확인하기 위해서 코드를 추가하였다.


……..
void Check_clEnqueueNDRangeKernel_Error(cl_int error)
{
    
    
switch( error )
    {
        
case CL_INVALID_PROGRAM_EXECUTABLE : printf("CL_INVALID_PROGRAM_EXECUTABLE\n"); break;
        
case CL_INVALID_COMMAND_QUEUE      : printf("CL_INVALID_COMMAND_QUEUE\n"); break;
        
case CL_INVALID_KERNEL            : printf("CL_INVALID_KERNEL\n");break;
        
case CL_INVALID_CONTEXT            : printf("CL_INVALID_CONTEXT\n");break;
        
case CL_INVALID_KERNEL_ARGS        : printf("CL_INVALID_KERNEL_ARGS\n"); break;
        
case CL_INVALID_WORK_DIMENSION    : printf("CL_INVALID_WORK_DIMENSION\n"); break;
        
case CL_INVALID_WORK_GROUP_SIZE    : printf("CL_INVALID_WORK_GROUP_SIZE\n") ; break;
        
case CL_INVALID_WORK_ITEM_SIZE    : printf("CL_INVALID_WORK_ITEM_SIZE\n"); break ;
        
case CL_INVALID_GLOBAL_OFFSET      : printf("CL_INVALID_GLOBAL_OFFSET\n"); break;
        
case CL_OUT_OF_RESOURCES          : printf("CL_OUT_OF_RESOURCES\n"); break;
        
case CL_MEM_OBJECT_ALLOCATION_FAILURE : printf("CL_MEM_OBJECT_ALLOCATION_FAILURE\n");break;
        
case CL_INVALID_EVENT_WAIT_LIST    : printf("CL_INVALID_EVENT_WAIT_LIST\n");break;
        
case CL_OUT_OF_HOST_MEMORY        : printf("CL_OUT_OF_HOST_MEMORY\n");break;       
    }   
}
….


추가된 코드에 의해서 

Number of OpenCL platforms found: 1
Number of detected OpenCL devices: 3
Running on CPU ........
=> Kernel name: copy2Dfloat4 with arity: 2
=> About to create command queue and enqueue this kernel...
Unable to enqueue task to command-queue: No such file or directory
CL_INVALID_WORK_GROUP_SIZE
Program ended with exit code: 1


과 같은 것을 얻을 수 있다.

확인하기 위해서 코드를 보면


            /* Enqueue the kernel to the command queue */
                
size_t globalThreads[2];
                globalThreads[
0]=1024;
                globalThreads[
1]=1024;
                
size_t localThreads[2];
                localThreads[
0] = 64;
                localThreads[
1] = 2;

                
cl_event evt;
            error = 
clEnqueueNDRangeKernel(    cQ,  // command queue
                                               kernels[j], // kernel
                                               
2,   // work_dim
                                               
0,   // global work_offset
                                               globalThreads, // global work size
                                               localThreads,  // local work_size
                                               
0,              // event related parameter
                                               
NULL, &evt);
                
clWaitForEvents(1, &evt);
            
if (error != CL_SUCCESS) { 
                
perror("Unable to enqueue task to command-queue");
                    
Check_clEnqueueNDRangeKernel_Error(error);
                
exit(1);
            }




으로 되어 있다.


계속 같은 에러가 나타나서 다음과 같이 디바이스 정보를 얻어내는 함수를 넣고 실행을 해 본다.


void displayDeviceDetails(cl_device_id id,
                          
cl_device_info param_name,
                          
const char* paramNameAsStr) {
    
cl_int error = 0;
    
size_t paramSize = 0;
    
    error = 
clGetDeviceInfo( id, param_name, 0NULL, &paramSize );
    
if (error != CL_SUCCESS ) {
        
perror("Unable to obtain device info for param\n");
        
return;
    }
    
    
/* the cl_device_info are preprocessor directives defined in cl.h */
    
switch (param_name) {
        
case CL_DEVICE_TYPE: {
            
cl_device_type* devType = (cl_device_type*) alloca(sizeof(cl_device_type) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, devType, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device info for param\n");
                
return;
            }
            
switch (*devType) {
                
case CL_DEVICE_TYPE_CPU : printf("CPU detected\n");break;
                
case CL_DEVICE_TYPE_GPU : printf("GPU detected\n");break;
                
case CL_DEVICE_TYPE_ACCELERATOR : printf("Accelerator detected\n");break;
                
case CL_DEVICE_TYPE_DEFAULT : printf("default detected\n");break;
            }
        }
break;
        
case CL_DEVICE_VENDOR_ID :
        
case CL_DEVICE_MAX_COMPUTE_UNITS :
        
case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS : {
            
cl_uint* ret = (cl_uint*) alloca(sizeof(cl_uint) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, ret, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device info for param\n");
                
return;
            }
            
switch (param_name) {
                
case CL_DEVICE_VENDOR_IDprintf("\tVENDOR ID: 0x%x\n", *ret); break;
                
case CL_DEVICE_MAX_COMPUTE_UNITSprintf("\tMaximum number of parallel compute units: %d\n", *ret); break;
                
case CL_DEVICE_MAX_WORK_ITEM_DIMENSIONSprintf("\tMaximum dimensions for global/local work-item IDs: %d\n", *ret); break;
            }
        }
break;
        
case CL_DEVICE_MAX_WORK_ITEM_SIZES : {
            
cl_uint maxWIDimensions;
            
size_t* ret = (size_t*) alloca(sizeof(size_t) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, ret, NULL );
            
            error = 
clGetDeviceInfo( id, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONSsizeof(cl_uint), &maxWIDimensions, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device info for param\n");
                
return;
            }
            
printf("\tMaximum number of work-items in each dimension: ( ");
            
for(cl_int i =0; i < maxWIDimensions; ++i ) {
                
printf("%d ", ret[i]);
            }
            
printf(" )\n");
        }
break;
        
case CL_DEVICE_MAX_WORK_GROUP_SIZE : {
            
size_t* ret = (size_t*) alloca(sizeof(size_t) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, ret, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device info for param\n");
                
return;
            }
            
printf("\tMaximum number of work-items in a work-group: %d\n", *ret);
        }
break;
        
case CL_DEVICE_NAME :
        
case CL_DEVICE_VENDOR : {
            
char data[48];
            error = 
clGetDeviceInfo( id, param_name, paramSize, data, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device name/vendor info for param\n");
                
return;
            }
            
switch (param_name) {
                
case CL_DEVICE_NAME : printf("\tDevice name is %s\n", data);break;
                
case CL_DEVICE_VENDOR : printf("\tDevice vendor is %s\n", data);break;
            }
        } 
break;
        
case CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE: {
            
cl_uint* size = (cl_uint*) alloca(sizeof(cl_uint) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, size, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device name/vendor info for param\n");
                
return;
            }
            
printf("\tDevice global cacheline size: %d bytes\n", (*size)); break;
        } 
break;
        
case CL_DEVICE_GLOBAL_MEM_SIZE:
        
case CL_DEVICE_MAX_MEM_ALLOC_SIZE: {
            
cl_ulong* size = (cl_ulong*) alloca(sizeof(cl_ulong) * paramSize);
            error = 
clGetDeviceInfo( id, param_name, paramSize, size, NULL );
            
if (error != CL_SUCCESS ) {
                
perror("Unable to obtain device name/vendor info for param\n");
                
return;
            }
            
switch (param_name) {
                
case CL_DEVICE_GLOBAL_MEM_SIZEprintf("\tDevice global mem: %ld mega-bytes\n", (*size)>>20); break;
                
case CL_DEVICE_MAX_MEM_ALLOC_SIZEprintf("\tDevice max memory allocation: %ld mega-bytes\n", (*size)>>20); break;
            }
        } 
break;
            
    } 
//end of switch
    
}



void displayDeviceInfo(cl_platform_id platform_id,
                       
cl_device_type dev_type) {
    
/* OpenCL 1.1 device types */
    
cl_int error = 0;
    
cl_uint numOfDevices = 0;
    
    
/* Determine how many devices are connected to your platform */
    error = 
clGetDeviceIDs(platform_id, dev_type, 0NULL, &numOfDevices);
    
if (error != CL_SUCCESS ) {
        
perror("Unable to obtain any OpenCL compliant device info");
        
exit(1);
    }
    
cl_device_id* devices = (cl_device_id*) alloca(sizeof(cl_device_id) * numOfDevices);
    
    
/* Load the information about your devices into the variable 'devices' */
    error = 
clGetDeviceIDs(platform_id, dev_type, numOfDevices, devices, NULL);
    
if (error != CL_SUCCESS ) {
        
perror("Unable to obtain any OpenCL compliant device info");
        
exit(1);
    }
    
printf("Number of detected OpenCL devices: %d\n", numOfDevices);
    
/* We attempt to retrieve some information about the devices. */
    
for(int i = 0; i < numOfDevices; ++ i ) {
        
displayDeviceDetails( devices[i], CL_DEVICE_TYPE"CL_DEVICE_TYPE" );
        
displayDeviceDetails( devices[i], CL_DEVICE_NAME"CL_DEVICE_NAME" );
        
displayDeviceDetails( devices[i], CL_DEVICE_VENDOR"CL_DEVICE_VENDOR" );
        
displayDeviceDetails( devices[i], CL_DEVICE_VENDOR_ID"CL_DEVICE_VENDOR_ID" );
        
displayDeviceDetails( devices[i], CL_DEVICE_MAX_MEM_ALLOC_SIZE"CL_DEVICE_MAX_MEM_ALLOC_SIZE" );
        
displayDeviceDetails( devices[i], CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE"CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE" );
        
displayDeviceDetails( devices[i], CL_DEVICE_GLOBAL_MEM_SIZE"CL_DEVICE_GLOBAL_MEM_SIZE" );
        
displayDeviceDetails( devices[i], CL_DEVICE_MAX_COMPUTE_UNITS"CL_DEVICE_MAX_COMPUTE_UNITS" );
        
displayDeviceDetails( devices[i], CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS"CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS" );
        
displayDeviceDetails( devices[i], CL_DEVICE_MAX_WORK_ITEM_SIZES"CL_DEVICE_MAX_WORK_ITEM_SIZES" );
        
displayDeviceDetails( devices[i], CL_DEVICE_MAX_WORK_GROUP_SIZE"CL_DEVICE_MAX_WORK_GROUP_SIZE" );
    }
}
..

결과는 아래와 같다.

Number of OpenCL platforms found: 1
Number of detected OpenCL devices: 3
Running on CPU ........
Number of detected OpenCL devices: 3
CPU detected
Device name is Intel(R) Core(TM) i7-3615QM CPU @ 2.30GHz
Device vendor is Intel
VENDOR ID: 0xffffffff
Device max memory allocation: 4096 mega-bytes
Device global cacheline size: 6291456 bytes
Device global mem: 16384 mega-bytes
Maximum number of parallel compute units: 8
Maximum dimensions for global/local work-item IDs: 3
Maximum number of work-items in each dimension: ( 1024 1 1  )
Maximum number of work-items in a work-group: 1024

GPU detected
Device name is GeForce GT 650M
Device vendor is NVIDIA
VENDOR ID: 0x1022700
Device max memory allocation: 256 mega-bytes
Device global cacheline size: 0 bytes
Device global mem: 1024 mega-bytes
Maximum number of parallel compute units: 2
Maximum dimensions for global/local work-item IDs: 3
Maximum number of work-items in each dimension: ( 1024 1024 64  )
Maximum number of work-items in a work-group: 1024

GPU detected
Device name is HD Graphics 4000
Device vendor is Intel
VENDOR ID: 0x1024400
Device max memory allocation: 256 mega-bytes
Device global cacheline size: 0 bytes
Device global mem: 1024 mega-bytes
Maximum number of parallel compute units: 16
Maximum dimensions for global/local work-item IDs: 3
Maximum number of work-items in each dimension: ( 512 512 512  )
Maximum number of work-items in a work-group: 512

numOfKernels : 1
=> Kernel name: copy2Dfloat4 with arity: 2
=> About to create command queue and enqueue this kernel



처음에는 잘 몰랐는데 보면 work item의 차원 수와 각 차원의 갯수를 알수 있다.

우선 CPU에서 실행하게 되므로 {1024 , 1 , 1 }이 할당 될 수 있다.
앞서의 코드에서


                size_t globalThreads[2];
                globalThreads[
0]=1024;
                globalThreads[
1]=1024;
                
size_t localThreads[2];
                localThreads[
0] = 64;
                localThreads[
1] = 2;


이 되어 있으므로 localThread를 2를 할당해서 그런 것이다.
수정을 해서 진행하면
넘어간다.



…    

                cl_event evt;
                error = 
clEnqueueNDRangeKernel(cQ, 
                                               kernels[j],
                                               
2,
                                               
0,
                                               globalThreads,
                                               localThreads,
                                               
0

                                               NULL, &evt); 
                clWaitForEvents(1, &evt);

에서 걸리는데


clWaitForEvents 을 호출하면 대기하는 동안 EXC_BAD_ACCESS 가 발생한다.
즉 잘못된 메모리를 참조 하는 것으로 발생하는 것이다.

이것은 event list의 오류로 보기 보다는 kernel에서 메모리 참조 오류로 보아야 하는게 아닌가 생각이 든다.

처음부터 찬찬히 보면은


#define DATA_SIZE (128*128)      // for test runs, 데이터의 크기는 128 * 128개의 크기이다.
….

main()
{
...
   cl_float* h_in = (float*) mallocsizeof(cl_float4) * DATA_SIZE); // input to device
   
cl_float* h_out = (float*) mallocsizeof(cl_float4) * DATA_SIZE); // output from device
   
forint i = 0; i < DATA_SIZE; ++i) {
        h_in[i] = (
float)i;
   }
  h_in에 (128*128)개의 공간을 할당하고 그 메모리를 초기화 한다.
...


위에서 코드를 보면 cl_float와 float 그리고 cl_float4가 혼용되어 있다.
이를 아래와 같이 수정해둔다.

...
    cl_float* h_in = (float*) mallocsizeof(cl_float) * DATA_SIZE); // input to device
    
cl_float* h_out = (float*) mallocsizeof(cl_float) * DATA_SIZE); // output from device
   
forint i = 0; i < DATA_SIZE; ++i) {
        h_in[i] = (
cl_float)i;
   }




   // Search for a CPU/GPU device through the installed platforms
   
// Build a OpenCL program and do not run it.
   
for(cl_uint i = 0; i < numOfPlatforms; i++ ) {
…..
    /* For each device, create a buffer and partition that data among the devices for compute! */
    
cl_mem memInObj = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR
                                    
sizeof(cl_float4) * (DATA_SIZE), h_in, &error);
    
if(error != CL_SUCCESS) {
        
perror("Can't create an input buffer object");
        
exit(1);
    }


        int offset = 0;

        
for(int i = 0; i < numOfDevices; ++i, ++offset ) {

            /* Loop thru each kernel and execute on device */
            
// 커널의 갯수 만큼 반복한다.
        
for(cl_uint j = 0; j < numOfKernels; j++) {

            cl_mem memOutObj = clCreateBuffer(context, CL_MEM_WRITE_ONLY ,
                                              
sizeof(cl_float4) * (DATA_SIZE), NULL, &error);
                
            
if(error != CL_SUCCESS) {
                
perror("Can't create an output buffer object");
                
exit(1);
            }

            /* Let OpenCL know that the kernel is suppose to receive two arguments */
            error = 
clSetKernelArg(kernels[j], 0sizeof(cl_mem), &memInObj);
            
if (error != CL_SUCCESS) { 
                
perror("Unable to set buffer object in kernel");
                
exit(1);
            }
                
            error = 
clSetKernelArg(kernels[j], 1sizeof(cl_mem), &memOutObj);
            
if (error != CL_SUCCESS) { 
                
perror("Unable to set buffer object in kernel");
                
exit(1);
            }


                // 커널을 커맨드 큐에 넣는다.
            
/* Enqueue the kernel to the command queue */
                
size_t globalThreads[3]= { 1024 , 2 , 1 };
                size_t localThreads[3] = { 128 , 1 , 1 } ;
                cl_event  evt ;//= new cl_event[1];

            error = 
clEnqueueNDRangeKernel(cQ, 
                                               kernels[j],
                                               
2,
                                               
0,
                                               globalThreads,
                                               localThreads,
                                               
0
                                               
NULL, &evt);
                
                
clWaitForEvents(1, (const cl_event*)&evt);


            /* Enqueue the read-back from device to host */
            error = 
clEnqueueReadBuffer(cQ, memOutObj,
                                        
CL_TRUE,               // blocking read
                                        
0,         // write from the last offset
                                        (
DATA_SIZE)*sizeof(cl_float4),           // how much to copy
                                        h_out, 
0NULLNULL);

                /* Check the returned data */
            
if ( valuesOK(h_in, h_out, DATA_SIZE) ) {
                
printf("Check passed!\n");
            } 
else printf("Check failed!\n");

            
/* Release the resources */
            
clReleaseCommandQueue(cQ);
            
clReleaseMemObject(memOutObj);
     }


이제 실행 결과를 보면 아래와 같다.

=> Task has been enqueued successfully!
Checking data of size: 16384
to:0.000000, from:0.000000
to:1.000000, from:1.000000
to:2.000000, from:2.000000
to:3.000000, from:3.000000
to:1.000000, from:0.000000

..
위와 같이 제대로 데이터가 카피가 안된다.

OpenCL 함수는 아래와 같이 코딩되어 있다.

#define WIDTH 128
#define DATA_TYPE float4

/* 
  The following macros are convenience 'functions' 
  for striding across a 2-D array of coordinates (x,y)
  by a factor which happens to be the width of the block
  i.e. WIDTH
*/

#define A(x,y) A[(x)* WIDTH + (y)]
#define C(x,y) C[(x)* WIDTH + (y)]
__kernel void copy2Dfloat4(__global DATA_TYPE *A, __global DATA_TYPE *C)
{
    
int x = get_global_id(0);
    
int y = get_global_id(1);
    
// its like a vector load/store of 4 elements
    C(x,y) = A(x,y);

}


global id를 두가지를 받아 와서 동작하돌고 만들어져 있다.


Kernel과 work item에 대해서 관계를 정리하면 아래와 같다.

커널은 하나의 워크 아이템에 대해서 한번만 실행이 된다.
각각의 워크 아이템은 하나의 private 메모리 공간을 가지고 있다.

워크 아이템을 묶어서 work group으로 나타내어 진다.
워크 그룹은 local memory를 가진다.

전체 워크 아이템의 갯수는 global work size로 명시된다.
global과 constant 메모리는 모든 워크 아이템과 워크 그룹 사이에서 공유된다





위의 그림에서
하나의 사각형은 워크 아이템을 나타낸다.
그리고 그룹핑된 박스는 워크 그룹을 나타낸다.

OpenCL은 Dimension이라는 개념을 기반으로 움직인다. 이것은 work item을  인덱스를 이용해서 선언할 수 있다는 의미이다.
위의 그림에서 work group의 크기는  Sx = 4 , Sy = 4 가 된다.
얼마나 큰 dimension을 사용 할 지는 전적으로 프로그래머에게 달려 있다.
그러나 전체적으로 물리적인 한계 때문에 그룹당 워크 아이템이라던가 global index등의 한계는 존재하게 된다.

커널의 내에서는 핸재의 커널이 할당된 work item의 위치를 물어 볼 수 있다.

get_global_id(dim) 

으로 알아 낼 수 있다.

위의 함수는 
 get_local_size(dim)*get_group_id(dim) + get_local_id(dim).
과 동일한 결과를 가지고 온디ㅏ.

 get_local_size(dim) : group size 
 get_group_id(dim) : group position in dim
 get_local_id(dim)  : he position of a work item relative to the group

 그림으로 나타내면 아래와 같다.




연산을 어떻게 할 것인가를 나타내기 위해서는 
현재의 위치를 알고 현재의 위치에 맞는 크기를 가지고 와야 한다.

global size는 global thread로 코드에 표시가 되는데

1024개의 글로벌 Size가 있다면

128 * 128 / 1024 = 16 이 되어야 한다.

local 은 global을 local단위로 잘라내는 역활을 한다.

            /* Enqueue the kernel to the command queue */
                
size_t globalThreads[3]= { 256 , 64 , 1 };
//                globalThreads[0]=1024;
//                globalThreads[1]=1024;
                
                
size_t localThreads[3] = { 128 , 1 , 1 } ;
//                localThreads[0] = 128;
//                localThreads[1] = 128;


위와 같이 되어 있다면

256 x 64의 global size를 가지게 된다.
이것을 128 x 1으로 나누어서 한번에 계산하게 되는 것이다.
 이때 Kernel은 현재의 위치를 알기 위해서는
global_id(0)와 global_id(1)을 확인해야 한다.

OpenCL에서

#define A(x,y) A[(x)* WIDTH + (y)]

#define C(x,y) C[(x)* WIDTH + (y)]

..
    int x = get_global_id(0);
    
int y = get_global_id(1);
..

으로 되어 있다.

따라서 global thread가 0/1/2가 있는데 0은 OpenCL에서 Index(0)를 1은 Index(1)을 반영한다.(고 가정할 수 있다.)
그렇게 되면 위에서 처럼 256 x 64 이면 16384가 되므로 (1024,1,1)을 초과하여서 안되고
일단 1024,1,1로만 한정하여서 다시 해본다.

                size_t globalThreads[3]= { 1024 , 1 , 1 };

로 지정하면 global thread의 개수가 1024개까지 실행이 된다고 볼 수 있다.

여기서 local thread는 global thread를 나누어서 실행하는 것을 의미한다.
여기서는 128,1,1로 되어 있다면 
1024를 8개 Work Group으로 나누어서 실행한다고 볼 수 있다.
즉 한번에 128개를 동시에 실행하는 것이다.

여기까지는 문제가 없다.

OpenCL Code를 보면

..
#define A(x,y) A[(x)* WIDTH + (y)]
#define C(x,y) C[(x)* WIDTH + (y)]
__kernel void copy2Dfloat4(__global DATA_TYPE *A, __global DATA_TYPE *C)
{
    
int x = get_global_id(0);
    
int y = get_global_id(1);
    
//int y = 0;
    
// its like a vector load/store of 4 elements
    C(x,y) = A(x,y);

}


위와 같은데 
위치를 계산하는 x와 y를 보면

x * width + y의 값을 가진다.
그런데 x가 index 0를 y가 index 1을 가지고 오고 있다.
x축과 y축으로 본다면 index 0와 index 1이 바뀐 것으로 볼 수 있다.

따라서 다음과 같이 한다.

..
    int x = get_global_id(1);
    
int y = get_global_id(0);

으로 하고 컴파일하면


from:1019.000000, to:1019.000000
from:1020.000000, to:1020.000000
from:1021.000000, to:1021.000000
from:1022.000000, to:1022.000000
from:1023.000000, to:1023.000000
Check passed!
Program ended with exit code: 0

..
으로 테스트가 통과하고 있다.
결국 OpenCL에서 Index의 선택이 잘 못되어 있었다.


그런데
local thread를
                size_t localThreads[3] = { 512 1 , 1 } ; —> FAIL
                size_t localThreads[3] = { 256 1 , 1 } ; —> FAIL
                size_t localThreads[3] = { 128 , 1 , 1 } ; —> WORK
로 된다.

Local Thread의 갯수가 128일때 동작을 한다.

이런 것을 일일이 찾아서 만드는 것이 귀찮으면, 그리고 플랫폼에 따른 커널의 일관성을 유지하기가 쉽지 않을 것 같으므로
Local Thread를 NULL로 해두면 OpenCL Compiler가 알아서 할당하게 된다.
아래 코드로 해도 정상적으로 실행이 된다.

..
            error = clEnqueueNDRangeKernel(cQ, 
                                               kernels[j],
                                               
2,
                                               
0,
                                               globalThreads,
                                               
NULL,
                                               
0
                                               
NULL, &evt);



테스트를 위해서 다음과 같이 크기를 변경하였다.

#define DATA_SIZE (128*128)      // for test runs,

그랬더니 다음과 같은 오류가 발생하였다.

...
=> Task has been enqueued successfully!
Checking data of size: 16384
from:4096.000000, to:0.000000
from:4097.000000, to:0.000000
from:4098.000000, to:0.000000
from:4099.000000, to:0.000000
Check failed!
Program ended with exit code: 0



4096에서 오류가 발생한 것이다.

복사가 안된 것이다.


                size_t globalThreads[3]= { 512 , 1 , 1 };
..

로 바꾼뒤에 다시 실행하면
=> Task has been enqueued successfully!
Checking data of size: 16384
from:2048.000000, to:0.000000
from:2049.000000, to:0.000000
from:2050.000000, to:0.000000
from:2051.000000, to:0.000000
Check failed!

..
으로 2048에서 오류가 발생한다.
마찬가지로

...
                size_t globalThreads[3]= { 256 , 1 , 1 };
...

=> Task has been enqueued successfully!
Checking data of size: 16384
from:1024.000000, to:0.000000
from:1025.000000, to:0.000000
from:1026.000000, to:0.000000
from:1027.000000, to:0.000000



1024일때 4096
512일 경우 2048
256 일 경우 1024
이후에 오류가 발생한다.
즉 Global Size * 4에서 부터 오류가 발생하는 것이다.

체크를 하기 위햇 더 프린트를 해 보면 아래와 같다.

Checking data of size: 16384
from:1024.000000, to:0.000000
from:1025.000000, to:0.000000
from:1026.000000, to:0.000000
from:1027.000000, to:0.000000
from:0.000000, to:0.000000
from:0.000000, to:0.000000
Check failed!



값이 1027 이후에는 아예 없어졌다.
현상은 두가지 이다. 하나는 1023까지는 정확하게 가는데
1024부터는 안가는 현상이고
두번째는 1027 이후 1028부터는 아예 데이터가 없다는 점이다.

원래 부터 없었는지 확인을 해보기 위해서 아래와 같은 코드를 넣어 보자

                printf("Before start check data \n");
                
printf("  from:%f, to:%f\n", h_in[1024+0] ,h_out[1024+0]);
                
printf("  from:%f, to:%f\n", h_in[1024+1] ,h_out[1024+1]);
                
printf("  from:%f, to:%f\n", h_in[1024+2] ,h_out[1024+2]);
                
printf("  from:%f, to:%f\n", h_in[1024+3] ,h_out[1024+3]);
                
printf("  from:%f, to:%f\n", h_in[1024+4] ,h_out[1024+4]);
..

결과는 아래와 같다.

Before start check data 
  from:1024.000000, to:0.000000
  from:1025.000000, to:0.000000
  from:1026.000000, to:0.000000
  from:1027.000000, to:0.000000
  from:0.000000, to:0.000000


우선 1028부터는 아예 값이 안들어간 문제부터 확인해보자

    forint i = 0; i < DATA_SIZE; ++i) {
          …      
    }

위의 코드를 보면

데이터 크기까지만 카피 하도록 되어 있다.
그런데 데이터 크기의 타입이 float4이므로 실제로는 그 4배가 되어야 한다.

    forint i = 0; i < DATA_SIZE*4; ++i) {
        h_in[i] = (
float)(i);
    }



위와 같이 수정하여서 실행하면 다음과 같은 결과를 얻는다.


Checking data of size: 16384
from:1024.000000, to:0.000000
from:1025.000000, to:0.000000
from:1026.000000, to:0.000000
from:1027.000000, to:0.000000
from:1028.000000, to:0.000000
from:1029.000000, to:0.000000
Check failed!
Program ended with exit code: 0

...
이제 문제중 두번째 문제는 해결 되었다.
첫번째 문제인 1024 이후에는 복사를 하지 않는 문제를 해결 해 보자

아까 말한대로 global thread의 4배까지만 복사해주는 문제가 있다.
이는 Enqueue하는 것이 global thread까지만 한다고 가정 할 수 있지 않을까 ?

그런데 여기서 전체적으로 작업해야 할 크기가 1024이고 float4이므로 실제로는 4096까지 간다는 것은 이해 할 수 있다.
한번 이것을 늘려 보자

그러면 

                size_t globalThreads[3]= { (128 * 128 / 4 ) , 1 , 1 };


으로 하면 

Running GPU ........
numOfKernels : 1
=> Kernel name: copy2Dfloat4 with arity: 2
=> About to create command queue and enqueue this kernel...
[0000] Before start check data 
  from:1024.000000, to:1024.000000
  from:1025.000000, to:1025.000000
  from:1026.000000, to:1026.000000
  from:1027.000000, to:1027.000000
  from:1028.000000, to:1028.000000
=> Task has been enqueued successfully!
Checking data of size: 16384
Check passed!


정확하게 종료 하는 것을 알 수 있다.

따라서 global thread  값은 실제 수행해야 하는 work item의 갯수를 의미한다.

이를 local thread로 나누어서 수행하는 것이다.

이제 일반화 시키기 위해서 다음과 같이 한다.

..
                size_t globalThreads[3]= { (DATA_SIZE / 4 ) , 1 , 1 };
...

그래도 결과는 성공적으로 끝난다.
이번에는 2차원으로 해보자

..
               size_t globalThreads[3]= { (DATA_SIZE / 4 ) >> 1  , 1 << 1 , 1 };
..

from:12288.000000, to:0.000000
from:12289.000000, to:0.000000
from:12290.000000, to:0.000000
from:12291.000000, to:0.000000
from:12292.000000, to:0.000000
from:12293.000000, to:0.000000
Check failed!

위에서 오류가 발생하였음을 알 수 있다.


                size_t globalThreads[3]= { (DATA_SIZE / 4 ) >> 1  , 1 << 1 , 1 };

에 대한 OpenCL에서 Code를 반영하지 않아서 생긴 문제이다.

...
#define WIDTH (16384/8)



으로 하면 정상적으로 실행이 된다.

                size_t globalThreads[3]= { (DATA_SIZE / 4 ) >> 2  , 1 << 2 , 1 };

#define WIDTH (16384/16)

위와 같이 되어도 정상적으로 동작을 한다.

정리하면

size_t globalThreads[3]= { (DATA_SIZE )   , 1   1 };
#define WIDTH (16384)

size_t globalThreads[3]= { (DATA_SIZE /2 )   , 1   1 };
#define WIDTH (16384/2)

size_t globalThreads[3]= { (DATA_SIZE / 4 )  , 1 1 };
#define WIDTH (16384/4)

size_t globalThreads[3]= { (DATA_SIZE / 8 )  , 2 , 1 };
#define WIDTH (16384/8)

size_t globalThreads[3]= { (DATA_SIZE / 16 )   , 4 , 1 };
#define WIDTH (16384/16)

가 정상적으로 동작하는 케이스이다.

2차원의 값이 증가하는 경우 숫자가 증가하므로 1차원의 숫자가 /2가 된다.





개념은 위와 같은 모델이 된다.
잘 생각해보면 당연한 이야기 이다.





'Computer Vision' 카테고리의 다른 글

증강 현실 테스트  (0) 2014.10.04
OpenCL::Query OpenCL kernel (4)  (0) 2014.05.02
OpenCL Test Program (3)  (0) 2014.03.31
OpenCL Test Program (2)  (0) 2014.03.18
OpenCL test program (1)  (0) 2014.03.15
Posted by GUNDAM_IM
Animation2014. 5. 7. 12:05




이것은 말로만 전해지던 건담 매뉴얼..

통칭 V 작전 매뉴얼이다.


.. 

.

.

.

갖고 싶다.


'Animation' 카테고리의 다른 글

루팡 3세 미네 후지코라는 여자  (0) 2014.08.17
지브리 멤버들의 회식~~  (0) 2013.08.15
아~~!! F.S.S.  (0) 2013.04.11
GUNDAM-AGE를 보면서~  (0) 2012.02.27
오늘은 LYNN MINMAY양의 생일입니다.  (0) 2011.10.10
Posted by GUNDAM_IM
Computer Vision2014. 5. 2. 13:16

이 프로그램은 OpenCL 코드를 불러들여서 컴파일하여서 kernel을 만드는데 까지 진행한다.

실행은 아직이다.


우선 크게 보면 main program에서 platform id를 확인하고 

platform id로 context를 만든다.


만들어진 context에 OpenCL 프로그램을 불러들여서 build를 하고 kernel로 준비해 준다.

그리고 해당 kernel의 정보를 받아와서 프린트 해 주는 데까지 진행한다.




OpenCL은 Runtime compile을 한다. 따라서 미리미리 컴파일을 해 고 진행하여야 한다.

이 예제에서는 Program과 Kernel을 만드는데 까지 진행한 예제이다.


(1) Platform ID의 개수를 확인한다.

(2) 확인된 Platform ID의 개수 만큼 공간을 확보한다.

(3) 확보된 메모리 공간에 Platform ID를 받아온다.

(4) Platform ID개수만큼 

     1) Device ID중 GPU 인것을 받아온다.

     2) GPU인 것이 없으면 CPU 인 것을 받아온다.

     3) Device ID에 Context를 생성한다.

     4) OpenCL 프로그램 소스를 로 드

     5) 로드된 프로그램소스를 빌드하여서 프로그램 화 한다.

         이 단계는 CreateProgramWithSource -> BuildProgram 을 거치는 2단계로 구성된다.

     6) 빌드 (컴파일)에서 문제가 생기면 그 정보(LOG)를 받아서 프린트 해준다.

 (5) clCreateKernelsInProgram 프로그램을 가지고 커널을 만든다.

      마찬가지로 2단계로 한다. 

      우선 커널의 개수를 확인하고

      확인된 커널의 개수만큼 메모리를 할당받고

      해당 할당받은 메모리에다가 커널을 빌드한다.

 (6) 확인된 커널의 개수만큼 

     1) 커널의 이름을 받아오고

     2) 인자의 개수를 받아온다.

     3) 받아온 커널의 이름과 인자의 개수를 프린트한다.



복잡하지만 줄여보면 다음과 같다.


기본 프레임은

  (1) 필요한 요소의 개수를 물어보고

  (2) 그만큼 메모리 공간을 할당 받고

  (3) 할당받은 메모리 공간에 요소를 받아온다.

이다. 


이것을 

 Platform ID -> Device ID -> context -> Kernel 

순으로 진행한다.

  


#include <stdio.h>
#include 
<stdlib.h>
#include 
<sys/types.h>
#include 
<alloca.h>

#ifdef __APPLE__
#include 
<OpenCL/cl.h>
#else
#include 
<CL/cl.h>
#endif

/*
 
프로그램을 읽어 들인다.
 OpenCL
 On-The-Fly Compile 수행한다.
 */

void loadProgramSource(const char** files,
                       
size_t length,
                       
char** buffer,
                       
size_t* sizes) {
    
    
/* Read each source file (*.cl) and store the contents into a temporary datastore */
    
for(size_t i=0; i < length; i++) {
        
FILE* file = fopen(files[i], "r");
        
if(file == NULL) {
            
perror("Couldn't read the program file");
            
exit(1);
        }
        
        
/* 파일의 끝까지 진행하여서 크기를 확인하고 다시 처음으로 돌아온다.*/
        
fseek(file, 0SEEK_END);
        sizes[i] = 
ftell(file);
        
rewind(file); // reset the file pointer so that 'fread' reads from the front
        
        
/* 크기 +1 만큼 할당한다음 */
        buffer[i] = (
char*)malloc(sizes[i]+1);
        buffer[i][sizes[i]] =  
'\0';
        
        
/* 한방에 읽어 들이다. */
        
fread(buffer[i], sizeof(char), sizes[i], file);
        
fclose(file);
    }
}

int main(int argc, char** argv) {
    
    
/* OpenCL 1.1 data structures */
    
cl_platform_id* platforms;
    
cl_program program;
    
cl_device_id device;
    
cl_context context;
    
    
/* OpenCL 1.1 scalar data types */
    
cl_uint numOfPlatforms;
    
cl_int  error;
    
    
/*
     Get the number of platforms
     Remember that for each vendor's SDK installed on the computer,
     the number of available platform also increased.
     */

    /* Step 1 : Platform ID의 개수를 확인한다. */
    error = 
clGetPlatformIDs(0NULL, &numOfPlatforms);
    
if(error != CL_SUCCESS) {
        
perror("Unable to find any OpenCL platforms");
        
exit(1);
    }
    
    /* Step 2 : 확인된 Platform ID의 개수만큼 메모리 공간을 확보한다. */
    platforms = (cl_platform_id*) alloca(sizeof(cl_platform_id) * numOfPlatforms);
    
printf("Number of OpenCL platforms found: %d\n", numOfPlatforms);
    
    /* Step 3 : 확보된 메모리 공간에 Platform ID 데이터를 받아온다. */
    error = clGetPlatformIDs(numOfPlatforms, platforms, NULL);
    
if(error != CL_SUCCESS) {
        
perror("Unable to find any OpenCL platforms");
        
exit(1);
    }
    
    
// GPU 찾는다.
    
// Search for a CPU/GPU device through the installed platforms
    
// Build a OpenCL program and do not run it.
    // Platform의 개수 만큼 진행한다.
    
for(cl_uint i = 0; i < numOfPlatforms; i++ ) {

        
// Get the GPU device
        // Step 1 : Device ID 중에서 GPU 인 것을  확인한다.
        error = 
clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_GPU1, &device, NULL);
        
if(error != CL_SUCCESS) {
            
// Otherwise, get the CPU
            // Step 1-1 : Device ID 중 GPU가 없으면 CPU인 것을 확인한다.
            error = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU1, &device, NULL);
        }
        
if(error != CL_SUCCESS) {
            
perror("Can't locate any OpenCL compliant device");
            
exit(1);
        }
        
        
/* Context 생성한다. */
        // Step 2 : Device ID에 Context를 생성한다.
        context = clCreateContext(NULL1, &device, NULLNULL, &error);
        
if(error != CL_SUCCESS) {
            
perror("Can't create a valid OpenCL context");
            
exit(1);
        }
        
        
/* Load the two source files into temporary datastores */
        
const char *file_names[] = {"/Users/freegear/Desktop/OpenCL/cl_test1/KernelQuery/KernelQuery/simple.cl""/Users/freegear/Desktop/OpenCL/cl_test1/KernelQuery/KernelQuery/simple_2.cl"};
        
const int NUMBER_OF_FILES = 2;
        
char* buffer[NUMBER_OF_FILES];
        
size_t sizes[NUMBER_OF_FILES];
        
loadProgramSource(file_names, NUMBER_OF_FILES, buffer, sizes);
        
        
/* OpenCL program object 생성한다.*/
        // Step 3 : Context에 프로그램 source를 컴파일하여 program을 생성한다.
        program = 
clCreateProgramWithSource(context, NUMBER_OF_FILES, (const char**)buffer, sizes, &error);
        
if(error != CL_SUCCESS) {
            
perror("Can't create the OpenCL program object");
            
exit(1);
        }
        
        
/* Build OpenCL program object and dump the error message, if any */
        
char *program_log;
        
const char options[] = "-cl-finite-math-only -cl-no-signed-zeros";
        
size_t log_size;
        
//error = clBuildProgram(program, 1, &device, argv[1], NULL, NULL);
        
// Uncomment the line below, comment the line above; re-build the program to use build options statically
        // Step 4: 생성된 프로그램을 빌드한다.
        error = clBuildProgram(program, 1, &device, options, NULLNULL);
        
        
if(error != CL_SUCCESS) {
            
// If there's an error whilst building the program, dump the log
            
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG0NULL, &log_size);
            program_log = (
char*) malloc(log_size+1);
            program_log[log_size] = 
'\0';
            
            // Step 4-1: 빌드 정보에 대한 Log를 확인한다.
            clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,
                                  log_size+
1, program_log, NULL);
            
            
printf("\n=== ERROR ===\n\n%s\n=============\n", program_log);
            
free(program_log);
            
exit(1);
        }
        
        
/* Query the program as to how many kernels were detected */
        
cl_uint numOfKernels;
        // Step 5 : Kernel의 개수를 학인한다.
        error = 
clCreateKernelsInProgram(program, 0NULL, &numOfKernels);
        
if (error != CL_SUCCESS) {
            
perror("Unable to retrieve kernel count from program");
            
exit(1);
        }
        
        // Step 6 : 확인된 Kernel의 개수만큼 메모리를 할당한다.
        
cl_kernel* kernels = (cl_kernel*) alloca(sizeof(cl_kernel) * numOfKernels);
        error = 
clCreateKernelsInProgram(program, numOfKernels, kernels, NULL);
        
        // Step 7 : 확인된 Kernel의 개수만큼 반복한다.
        for(cl_uint i = 0; i < numOfKernels; i++) {
            
char kernelName[32];
            
cl_uint argCnt;
            // Step 7-1 : 확인된 Kernel의 이름을 받아온다.
            clGetKernelInfo(kernels[i], CL_KERNEL_FUNCTION_NAMEsizeof(kernelName), kernelName, NULL);
            // Step 7-2 : 확인된 Kernel 인자의 개수를 받아온다.
            clGetKernelInfo(kernels[i], CL_KERNEL_NUM_ARGSsizeof(argCnt), &argCnt, NULL);
            
printf("Kernel name: %s with arity: %d\n", kernelName, argCnt);
        }
        
     
        
/* Clean up */
        // Step 8 :  청소하기
        
for(cl_uint i = 0; i < numOfKernels; i++) { clReleaseKernel(kernels[i]); }
        
for(i=0; i< NUMBER_OF_FILES; i++) { free(buffer[i]); }
        
clReleaseProgram(program);
        
clReleaseContext(context);
    }
}


실행 결과는 아래와 같다.


Number of OpenCL platforms found: 1

Kernel name: simpleAdd with arity: 3

Kernel name: simpleAdd_2 with arity: 3

Program ended with exit code: 0


찾아낸 플랫폼의 개수는 1개이고 여기서 포함되는 커널의 개수는 2개이다.

각각 

   simpleAdd

   simpleAdd_2

가 된다.




OpenCL source 코드는 아래와 같이 되어 있고 여기서는 아직 중요한 포인트가 아니므로 그냥 넘어간다.


 simple.cl


__kernel void simpleAdd(__global float *a,

                   __global float *b,

                   __global float *c) {

   

   *c = *a + *b;

}


simple_2.cl

__kernel void simpleAdd_2(__global float *a,

                   __global float *b,

                   __global float *c) {

   

   *c = *a + *b;

}



'Computer Vision' 카테고리의 다른 글

증강 현실 테스트  (0) 2014.10.04
OpenCL : Using work item to partition data (5)  (1) 2014.06.01
OpenCL Test Program (3)  (0) 2014.03.31
OpenCL Test Program (2)  (0) 2014.03.18
OpenCL test program (1)  (0) 2014.03.15
Posted by GUNDAM_IM
Books2014. 4. 24. 17:45

작은 회사 사장의 전략




- 이노우에 다쓰야

- 마일스톤 출판사


회사를 설립하고 3년이 지나면 약 35%가 도산하거나 폐업해서 사라진다고 한다.

이 비율은 다시 5년이면 85%의 회사가

10년이 되면 존속 가능한 회사는 6.3% 정도이다.

20년 이상 유지되는 회사는 0.3%에 불과하다.

결국 99.7%의 회사가 20년 내에 다 없어진다.


그리고 다시 20년 존속된 회사를 100개 모아놓고 10년을 보아도 존속한 회사는 다시 이 회사들 중에서 10%에 불과하다.

결국 30년이 되어도 살아 남는 회사는 0.03%에 불과하다는 의미이다.



이 책은 이런 상황에서 중소기업으로 20년 이상을 살아온 (엄밀하게는 버텨온 ) 회사 사장이 경험을 가지고 충고하는 책이다. 여러가지 경험적인 이야기를 많이 하고 있어서 책을 읽으면 많이 도움이 된다.


- 회사를 망치는 사장의 착각 9가지

  1. 어떤 상품이던지 조금씩이나마 팔리는 비극

  2. 적자 회사는 애초에 존재하지 않는다.

  3. 한가지에만 기대면 리스크가 클꺼야

  4. (대기업을 흉내내어서) 손대지 말아야할 상품에 손을 댄다

  5. 판매 대리점에서 신경써서 팔아주겠지

  6. 내 뒤에는 든든한 백이 있어 !!

  7. 이정도 가격이면 적당한 것 같다.

  8. 부자를 상대해야 큰 돈을 벌수 있다.

  9. 본업 이외에 다른 일에서 올리는 수수료도 쏠쏠할 것 같다.


작가는 이런 착각에서 벗어나거나 대응하는 방법을 의외로 보편적인 생각을 가지는 것이 중요하다고 이야기한다.

보편적인 생각을 가지지 못하기 떄문에 망하는 것이라고 한다.

- 보편적인 생각 9가지

 1. 아무도 원하지 않는 상품은 팔리지 않는다.

 2. 알기 쉬운 상품을 판다

 3. 지명도가 높은 쪽이 팔린다.

 4. 회사는 반드시 매출을 늘리는 일을 해야 한다.

 5. 고객만 광고를 보는 것이 아니다.

 6. 반드시 터무니 없는 짓을 하는 사람도 (시장 경쟁에) 참여 한다.

 7. 같은 일이라도 비지니스 모델이 다를 때가 있다.

 8. 대박이라는 이야기는 (가능성이 정말 높다고 보여도) 절반만 믿어라 

     - 믿지 말라와 같은 이야기이다.

 9. 세상은 공정하지 않다.



이러한 이야기를 바탕으로

- 제 2장 성공을 준비하는 앞선 계획

  그런데 엄밀하게는 미리 필요한 것을 준비하라는 의미이지 거창하게 1~20년을 내다 보라는 의미는 아니다.   

  다른 사람들 보다 좀더 빨리 그리고 필요한 만큼 멀리 볼 수 있는 것이 중요한 것 같다.

  

- 제 3장 사장의 인관 관계

  가난을 부르는 사람과 복을 부르는 사람을 구분하라는 의미인데

  재미 있는 점은 가난을 부르는 사람은 가난을 부르는 사람끼리 뭉쳐 있지 않고 가난을 부르는 사람과 복을 부르는 사람이 함께 있다는 점이다.


- 제 4장 사장의 직원

   직원을 키워야 하고

   혼자 하던 일을 줄떄에는 1명에게 주지 말고 3명 정도에게 나누어 주어야 한다. 

   - 그게 사장과 직원의 차이이다.

 

- 제 5장 성공하는 사장의 공통 전략




책의 내용을 한줄로 요약하면


- 공정하지 않은 비지니스 세계에서 자신만의 중심을 가지고 움직여라

  


Posted by GUNDAM_IM
Books2014. 4. 22. 11:18

미친듯이 심플 : 스티브 잡스, 불멸의 경영 무기 

켄 시걸 저/김광수 역 | 문학동네 | 2014년 04월 



스티브 잡스와 오랜 기간동안 보조를 맞추었던 마케팅 담당자의 스티브 잡스에 대한 보고서

엄청난 스티브"빠"의 면모를 볼 수 있다.


단순함의 위력을 활용하기 위해서는


- 작게 생각하라

- 가동성을 생각하라

- 상징을 생각하라

- 표현 방식을 생각하라

- 평소처럼 생각하라

- 인간을 생각하라

- 회의적으로 생각하라

- 전쟁을 생각하라


대부분의 내용을 관료적인 집단이 된 대기업과 잡스가 나서서 결정하고 빠르게 움직이는 작은 팀인 애플과의 효율성에 대한 비교에 할당하고 있다.


여러가지 잡스의 행적을 가지고 이야기를 진행하고 있기 때문에 역시 잡스"빠"라면 볼만 한 책이다.


애플에서 가지고 있는 단순함의 마법이라 하는 "Simple Stick"으로 이 책을 친다면


- 애플과 잡스를 좋아하면 볼만한 책이다.


로 요약할 수 있다.






Posted by GUNDAM_IM