Skip to content

**** ****

for my bad memories..

Vector 속도 테스트

2021-03-29


이미 요소의 갯수를 알고 있을때의 속도 테스트를 해봄..
테스트 비교는
Raw Array, C로 구현된 Vector (https://github.com/goldsborough/vector), C++ FBVctor (https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md), C++ Standard Vector

#include <iostream>
#include <chrono>

#include <folly/memory/Malloc.h>
#include <folly/FBVector.h>

#include <vector>

#include <vector/vector.h>

int main(void)
{
	{
		std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

		unsigned int *vec = (unsigned int *)malloc(1000000000 * sizeof(unsigned int));

		for(unsigned int i=0; i<1000000000; i++) {
			vec[i] = i;
		}

		std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
		std::cout << "array: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

		std::cout << "Press any key to next test." << std::endl;
		getchar();
		
		free(vec);
	}

	{
		std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

		Vector vec;
		vector_setup(&vec, 1000000000, sizeof(unsigned int));

		for(unsigned int i=0; i<1000000000; i++) {
			vector_push_back(&vec, &i);
		}

		std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
		std::cout << "C Vector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

		std::cout << "Press any key to next test." << std::endl;
		getchar();
		
		vector_clear(&vec);
		vector_destroy(&vec);
	}

	{
		std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

		folly::fbvector<unsigned int> vec;
		vec.reserve(1000000000);
		for(int i=0; i<1000000000; i++) {
			vec.push_back(i);
		}

		std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
		std::cout << "C++ FBVector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

		std::cout << "Press any key to next test." << std::endl;
		getchar();
		
		vec.clear();
		vec.shrink_to_fit();
	}

	{
		std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

		std::vector<unsigned int> vec;
		vec.reserve(1000000000);
		for(int i=0; i<1000000000; i++) {
			vec.push_back(i);
		}

		std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
		std::cout << "C++ Vector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

		std::cout << "Press any key to exit." << std::endl;
		getchar();

		vec.clear();
		vec.shrink_to_fit();
	}

	return 0;
}
array: Time passed (sec) : 2.27096 seconds
Press any key to next test.

C Vector: Time passed (sec) : 11.588 seconds
Press any key to next test.

C++ FBVector: Time passed (sec) : 6.22477 seconds
Press any key to next test.

C++ Vector: Time passed (sec) : 14.0583 seconds
Press any key to exit.

결과는 Raw Array 가 가장 빠름.


PHP 에서 특정 국가만 허용하기

2021-03-12


tcltk.co.kr 에서 drupal 을 사용중인데..
자꾸 스팸 글과 스팸 유저 때문에 골머리를 썩어서.. 시간좀 내서 알아봤음.

IP2Location (https://github.com/chrislim2888/IP2Location-PHP-Module)이라는 php 모듈이 있는걸 찾았고..
아래와 같이 druapl index.php 에 적용.

우선 IP2Location 폴더를 적절히 만들고 파일을 업로드하고 아래와 같이 한국 국가만 접근 가능토록 코드를 작성.

include DRUPAL_ROOT . '/IP2Location/Database.php';
include DRUPAL_ROOT . '/IP2Location/IpTools.php';
include DRUPAL_ROOT . '/IP2Location/WebService.php';

$db = new \IP2Location\Database(DRUPAL_ROOT . '/IP2Location/IP2LOCATION-LITE-DB1.BIN', \IP2Location\Database::FILE_IO);
$records = $db->lookup($_SERVER['REMOTE_ADDR'], \IP2Location\Database::ALL);

$countryCode = $records['countryCode'];
//echo $records['countryName'] . "- (".$records['countryCode'].")";

if($countryCode != 'KR') {
	echo 'You are connected from ' . $records['countryName'] . '.</br>';
	echo 'Only Korea(Republic of) country is allowed.';
	exit;
}

적용후 vpn 으로 접속하면..

흐흐.. 일단 잘됨. 이제 골머리는 썩지 않겠지?..
근데 이게 좋은 선택일까..


GNU utilities for Win32

2021-01-21


http://unxutils.sourceforge.net/

GNU 유틸리티중 유용한게 상당히 많은데..
이를 윈도우즈에서 사용할수 Win32로 포팅한 프로젝트가 GNU utilities for Win32 임.
물론 오래된 버전을 기준으로 하지만 dll 의존성 없이 딱딱 exe 하나만 있으면 사용가능하기에 아주 유용함.

먼저 아래의 파일을 받고.. usr/local/wbin 폴더내의 파일들 적당한곳에풀고
https://sourceforge.net/projects/unxutils/files/unxutils/current/UnxUtils.zip/download

다음 아래의 파일을 다운받아.. 기능개선 패치를 한다.
http://unxutils.sourceforge.net/UnxUpdates.zip

이제 사용하면된다.


Python 무설치 버전

2021-01-21


파이썬 공식 홈페이지에 무설치 버전을 제공하고 있음.
(https://www.python.org/downloads/release/python-391/)

아래로 쭉 내리다면 Windows embeddable package (64-bit) 이걸 받는다.

무설치 버전의 최고의 장점은 폴더채로 들고 다니면 어디서든 사용가능한 장점이 있음.
또 다른 응용 프로그램에 포함시켜서 파이썬의 기능을 이용할수도 있고..

어쨌든.. zip 파일을 다운받아 압축을 풀면 바로 사용가능함.
근데 문제는 pip 가 없다? pip가 없으면 외부 모듈 설치가 난감함.

pip 설치는 다음과 같이..
get-pip.py 를 아래에서 다운받아 적절한 폴더에 넣어둔다.
https://bootstrap.pypa.io/get-pip.py

다음 아래와 같이 설치한다.

C:\python-3.9.0-embed-amd64>python get-pip.py
Collecting pip
  Using cached pip-20.3.3-py2.py3-none-any.whl (1.5 MB)
Collecting setuptools
  Downloading setuptools-51.3.3-py3-none-any.whl (786 kB)
     |████████████████████████████████| 786 kB 1.6 MB/s
Collecting wheel
  Downloading wheel-0.36.2-py2.py3-none-any.whl (35 kB)
Installing collected packages: pip, setuptools, wheel
  WARNING: The scripts pip.exe, pip3.9.exe and pip3.exe are installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The scripts easy_install-3.9.exe and easy_install.exe are installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script wheel.exe is installed in 'C:\python-3.9.0-embed-amd64\Scripts' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed pip-20.3.3 setuptools-51.3.3 wheel-0.36.2

C:\python-3.9.0-embed-amd64>

이제 모듈을 설치할려고하니.. 이런 에러가..

C:\python-3.9.0-embed-amd64>Scripts\pip.exe install python-pptx
Traceback (most recent call last):
  File "runpy.py", line 197, in _run_module_as_main
  File "runpy.py", line 87, in _run_code
  File "C:\python-3.9.0-embed-amd64\Scripts\pip.exe\__main__.py", line 4, in <module>
ModuleNotFoundError: No module named 'pip'

파이썬 폴더에 보면 python39._pth 파일이 있는데 이 파일 마지막에 아래를 추가.

lib\site-packages

다시 설치하면

C:\python-3.9.0-embed-amd64>scripts\pip install python-pptx
Collecting python-pptx
  Downloading python-pptx-0.6.18.tar.gz (8.9 MB)
     |████████████████████████████████| 8.9 MB 6.4 MB/s
Collecting lxml>=3.1.0
  Downloading lxml-4.6.2-cp39-cp39-win_amd64.whl (3.5 MB)
     |████████████████████████████████| 3.5 MB ...
Collecting Pillow>=3.3.2
  Downloading Pillow-8.1.0-cp39-cp39-win_amd64.whl (2.2 MB)
     |████████████████████████████████| 2.2 MB ...
Collecting XlsxWriter>=0.5.7
  Downloading XlsxWriter-1.3.7-py2.py3-none-any.whl (144 kB)
     |████████████████████████████████| 144 kB ...
Building wheels for collected packages: python-pptx
  Building wheel for python-pptx (setup.py) ... done
  Created wheel for python-pptx: filename=python_pptx-0.6.18-py3-none-any.whl size=275704 sha256=968c6fae2111efebcae960370fb4ed5ceb311d0fa762f19fc82a9994aba754b6
  Stored in directory: c:\users\ihmin\appdata\local\pip\cache\wheels\94\b7\70\0c19e32b072e500447ae9a17df9389fc046973ef1df8b0c239
Successfully built python-pptx
Installing collected packages: XlsxWriter, Pillow, lxml, python-pptx
Successfully installed Pillow-8.1.0 XlsxWriter-1.3.7 lxml-4.6.2 python-pptx-0.6.18

정상 설치됨.


ffmpeg 프레임 추출 예제

2021-01-18


ffmpeg 을 이용한 비디오 파일에서 첫 다섯개의 프레임 이미지 추출 예제..

makefile

all:
	gcc ./test.c -I/c/Temp/ffmpeg_win65/include -L/c/Temp/ffmpeg_win64/lib -lavformat -lavcodec -lswscale -lavutil -lswresample -lz -lbcrypt -lole32 -lMfplat -ltiff -liconv -llzma -lws2_32 -lSecur32 -lbz2 -lstrmiids

test.c

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>

#include <stdio.h>

// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif

void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
  FILE *pFile;
  char szFilename[32];
  int  y;
  
  // Open file
  sprintf(szFilename, "frame%d.ppm", iFrame);
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;
  
  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);
  
  // Write pixel data
  for(y=0; y<height; y++)
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
  
  // Close file
  fclose(pFile);
}

int main(int argc, char *argv[]) {
  // Initalizing these to NULL prevents segfaults!
  AVFormatContext   *pFormatCtx = NULL;
  int               i, videoStream;
  AVCodecContext    *pCodecCtxOrig = NULL;
  AVCodecContext    *pCodecCtx = NULL;
  AVCodec           *pCodec = NULL;
  AVFrame           *pFrame = NULL;
  AVFrame           *pFrameRGB = NULL;
  AVPacket          packet;
  int               frameFinished;
  int               numBytes;
  uint8_t           *buffer = NULL;
  struct SwsContext *sws_ctx = NULL;

  if(argc < 2) {
    printf("Please provide a movie file\n");
    return -1;
  }
  // Register all formats and codecs
  av_register_all();
  
  // Open video file
  if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(avformat_find_stream_info(pFormatCtx, NULL)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  av_dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  
  // Get a pointer to the codec context for the video stream
  pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
  // Find the decoder for the video stream
  pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
  if(pCodec==NULL) {
    fprintf(stderr, "Unsupported codec!\n");
    return -1; // Codec not found
  }
  // Copy context
  pCodecCtx = avcodec_alloc_context3(pCodec);
  if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
    fprintf(stderr, "Couldn't copy codec context");
    return -1; // Error copying codec context
  }

  // Open codec
  if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
    return -1; // Could not open codec
  
  // Allocate video frame
  pFrame=av_frame_alloc();
  
  // Allocate an AVFrame structure
  pFrameRGB=av_frame_alloc();
  if(pFrameRGB==NULL)
    return -1;

  // Determine required buffer size and allocate buffer
  numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
            pCodecCtx->height);
  buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

  // Assign appropriate parts of buffer to image planes in pFrameRGB
  // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
  // of AVPicture
  avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
     pCodecCtx->width, pCodecCtx->height);
  
  // initialize SWS context for software scaling
  sws_ctx = sws_getContext(pCodecCtx->width,
         pCodecCtx->height,
         pCodecCtx->pix_fmt,
         pCodecCtx->width,
         pCodecCtx->height,
         AV_PIX_FMT_RGB24,
         SWS_BILINEAR,
         NULL,
         NULL,
         NULL
         );

  // Read frames and save first five frames to disk
  i=0;
  while(av_read_frame(pFormatCtx, &packet)>=0) {
	  // Is this a packet from the video stream?
	  if(packet.stream_index==videoStream) {
		  // Decode video frame
		  avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
		  // Did we get a video frame?
		  if(frameFinished) {
			  //avcodec_align_dimensions2 (pCodecCtx, &pCodecCtx->width, &pCodecCtx->height, pFrameRGB->linesize);

			  // Convert the image from its native format to RGB
			  sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
					  pFrame->linesize, 0, pCodecCtx->height,
					  pFrameRGB->data, pFrameRGB->linesize);

			  // Save the frame to disk
			  if(++i<=5)
				  SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
		  }
	  }

	  // Free the packet that was allocated by av_read_frame
	  av_free_packet(&packet);
  }
  
  // Free the RGB image
  av_free(buffer);
  av_frame_free(&pFrameRGB);
  
  // Free the YUV frame
  av_frame_free(&pFrame);
  
  // Close the codecs
  avcodec_close(pCodecCtx);
  avcodec_close(pCodecCtxOrig);

  // Close the video file
  avformat_close_input(&pFormatCtx);
  
  return 0;
}

FBVector

2021-01-05


페이스북에서 공개한 FBVector..
(https://github.com/facebook/folly/blob/master/folly/docs/FBVector.md)
FBVector는 folly의 일부분으로 std::vector 를 대체하기위한 용도.
(folly는 C++의 std나 boost 라이브러리의 일부분을 개선하거나 대체 용도로 개발된 클래스 모음.)

일단 테스트해보니.. 속도면에서 상당한 개선이..

{
	std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

	folly::fbvector<unsigned int> vec;
	for(int i=0; i<1000000000; i++) {
		vec.push_back(i);
	}

	std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
	std::cout << "FBVector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

	std::cout << "Press any key to next test." << std::endl;
	getchar();
	
	vec.clear();
	vec.shrink_to_fit();
}

{
	std::chrono::system_clock::time_point start = std::chrono::system_clock::now();

	std::vector<unsigned int> vec;
	for(int i=0; i<1000000000; i++) {
		vec.push_back(i);
	}

	std::chrono::duration<double> sec = std::chrono::system_clock::now() - start;
	std::cout << "Vector: Time passed (sec) : " << sec.count() << " seconds" << std::endl;

	std::cout << "Press any key to exit." << std::endl;
	getchar();

	vec.clear();
	vec.shrink_to_fit();
}

실행..

FBVector: Time passed (sec) : 9.05379 seconds
Press any key to next test.

Vector: Time passed (sec) : 16.3373 seconds
Press any key to exit.

ccache

2021-01-05


컴파일 속도 올리는 프로그램중 ccache 를 테스트해봄.

우선 ccache 설치

pacman --needed -S mingw-w64-x86_64-ccache

다음 .bashrc 에 추가

export USE_CCACHE=1
export CCACHE_DIR=/var/ccache-cache
export CCACHE_LOGFILE=/var/log/ccache.log

qmake의 pro 파일의 경우.. 아래를 추가

QMAKE_CXX=ccache g++

이제 컴파일을 하면..
첫번째 컴파일에는 캐시를 만드느라 시간이 들지만..
두번째부터는.. 엄청 빠른 시간에 컴파일을 수행함.


Single-pass Wireframe Rendering

2020-12-23


OpenGL 에서 정말 난이도가 높은것 중 하나가 와이어프레임을 그리는것이라 생각함..
이유는 면위에 선을 그리는거 자체가 간섭이 일어나기에 선이 제대로 보이지 않고..
면을 Offset 하지 않으면 도통 깨끗한 라인을 볼수 없다는것.. (OpenGL에서 선을 offset 하는 기능은 없음)
이것도 문제가 면을 Offset 하기 때문에 간혹 면과 다른 면의 선이 간섭이 발생하는것처럼 보이기도함..
그래서 선을 geometry 스테이징에서 아주 앏은 quad로 변환하여 Offset 해도 마찬기로 간섭이 발생하는것처럼 보이기도함..
어쨌던 이래나 저래나 Wireframe을 그리는 단계가 추가되기 때문에 속도 저하가 아주 약간이라도 있기마련..

면을 그릴때 선을 같이 쉐이더에서 그릴수는 없을까 생각하다 구글링을 해보니.. 아래의 논문이 보임..

imm4884.pdf

확인해보니.. fragment 스테이징에서 primitive의 최외각을 추출해서 선을 그려주는 아주 간단하면서
속도 저하가 없는 아주 깨끗한 라인을 그릴수 있는 기법이란걸 알앗음.

해당 논문을 구현한 싸이트가 보이는데..
http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html
http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html

혹시 싸이트가 언제 짤릴지 모르니 아래는 백업 pdf…
Clipping Space_ Single-Pass Wireframe Rendering.pdf
Clipping Space_ Single-Pass Wireframe Rendering Explained and Extended.pdf

최종 구현 결과는…