2014/10/08(水)memory test

メモリテストプログラム

いわゆるPCのmemtestがそう。
PCとは異なるアーキテクチャでも、特に組込み危機でも必要となるでしょう。
この記事は、メモ代わりに記載するだけで本体に価値はありません・・・。
(オフラインで資料を作る際に参考にさせていただいた時のメモ)

メモリテストの目的や達成目標を明確にすることで、必要十分なものを選択しましょう。
(過去の踏襲…とか、非論理的なシゴトは決してしないように、なぁ。)

参考

メモリテストに関するよい記事

http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C

掲示板には20年の職人が来ている

http://stackoverflow.com/questions/3729544/free-implementation-of-march-memory-testing-algorithm
>Memory testing with cache
>Permalink Submitted by krishnakoyalmannam on Thu, 2011-05-19 02:00.
When you are testing external DDR2 memory on a multicore system,
 with a shared Level 2 Cache,
 each core could be assigned a dedicated section of memory to test and all the cores memory tests in parallel.
This causes the L2 cache to result in more cache miss than cache hit,
 thereby resulting in increased DRAM bus transactions,
 which could be very useful during HW Board BringUp.
And yes, the ground bounce and cross-talk tests do check for signal integrity problems. There is also MARCH-B and MARCH-C memory testing algorithms that sweep memory with random patterns in one direction and sweep in the reverse direction, so, a cache flush would be required before starting the reverse sweep. And finally, an XOR test to uncover memory cell faults, would make the suite of memory tests quite comprehensive providing greater coverage.

マーチアルゴリズム:LSIテスト用だなぁ

http://www.ece.uc.edu/~wjone/
http://www.ece.uc.edu/~wjone/Memory.pdf

2013/01/08(火)sigprocmaskの検証

Linux実装は pthread*のマスクと sigprocmask()とは同じって書いてた。。
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>

#define gettid() syscall(SYS_gettid)

// 0: sigprocmask at process, 1:thr1, 
#define DF_CHGMASK_ID 2
//#define DF_USE_PTHREADMASK
//#define DF_INITIAL_MASK (SIGSEGV)
//#define DF_INITIAL_MASK (SIGABRT)
#define DF_INITIAL_MASK (12)


void abt_handler(int n, siginfo_t *pSigInf, void *pContext)
{
struct sigaction sa;

	printf("I am dead...[%d][parent:%d][tid=%d][thread_id=%ld]", getpid(), getppid(), gettid(), (long)pthread_self());
	memset(&sa,0,sizeof(struct sigaction));
//_exit(1);
	sigemptyset(&sa.sa_mask);
//	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_handler = SIG_DFL;
//	sigaction(SIGABRT,&sa,NULL);
//	raise(SIGABRT);
}

void register_handler()
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = abt_handler;
//	sigaction(SIGABRT,&sa,NULL);
	sigaction( 12,&sa,NULL);
}


struct st_signals_st {
	int signo;
	const char *pcSignal ;
	} st_signals[] = {
			{SIGHUP,    "SIGHUP"},
			{SIGINT,    "SIGINT"},
			{SIGQUIT,   "SIGQUIT"},
			{SIGILL,    "SIGILL"},
			{SIGTRAP,   "SIGTRAP"},
			{SIGABRT,   "SIGABRT"},
			{SIGIOT,    "SIGIOT"},
			{SIGBUS,    "SIGBUS"},
			{SIGFPE,    "SIGFPE"},
			{SIGKILL,   "SIGKILL"},
			{SIGUSR1,   "SIGUSR1"},
			{SIGSEGV,   "SIGSEGV"},
			{SIGUSR2,   "SIGUSR2"},
			{SIGPIPE,   "SIGPIPE"},
			{SIGALRM,   "SIGALRM"},
			{SIGTERM,   "SIGTERM"},
			{SIGSTKFLT, "SIGSTKFLT"},
			{SIGCHLD,   "SIGCHLD"},
			{SIGCONT,   "SIGCONT"},
			{SIGSTOP,   "SIGSTOP"},
			{SIGTSTP,   "SIGTSTP"},
			{SIGTTIN,   "SIGTTIN"},
			{SIGTTOU,   "SIGTTOU"},
			{SIGURG,    "SIGURG"},
			{SIGXCPU,   "SIGXCPU"},
			{SIGXFSZ,   "SIGXFSZ"},
			{SIGVTALRM, "SIGVTALRM"},
			{SIGPROF,   "SIGPROF"},
			{SIGWINCH,  "SIGWINCH"},
			{SIGIO,     "SIGIO"},
			{SIGPOLL,   "SIGPOLL"},
			{SIGPWR,    "SIGPWR"},
			{SIGSYS,    "SIGSYS"},
			{0, NULL}
		} ;

void dump_sigmask(const char* pMsg, sigset_t* sig_mask)
{
struct st_signals_st* pStSignal = st_signals ;
int i;
	puts(pMsg);
	while( pStSignal->pcSignal ){
		if (sigismember( sig_mask, pStSignal->signo )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
		pStSignal++;
	}
	putchar('_');
	for (i=SIGRTMIN; i<=SIGRTMAX; i++) {
		if (sigismember( sig_mask, i )) {
			putchar('1');
		}
		else {
			putchar('0');
		}
	}
	puts("");
return ;
}


void* thr1(void* arg)
{
sigset_t sig_mask ;

	sleep(1);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr1!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigfillset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);

#if (DF_CHGMASK_ID==1)
	sigemptyset(&sig_mask);
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_SETMASK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
#endif
		perror ("main(): failure set...");
	}
#endif
	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr1", &sig_mask);
	sleep(10);
}

void* thr2(void* arg)
{
sigset_t sig_mask ;

	register_handler();
//	sigaddset(&sig_mask, DF_INITIAL_MASK) ;

	sigemptyset(&sig_mask);
	sigaddset(&sig_mask, 12) ;
#ifdef DF_USE_PTHREADMASK
	if (pthread_sigmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#else
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
#endif
		perror ("thr2(): Dead set...");
	}


	sleep(2);
printf("[%d/ppid=%d/tid=%d/self=%ld] wakeup thr2!\n", getpid(), getppid(), gettid(), (long)pthread_self());
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	sleep(4);
	pthread_sigmask(SIG_UNBLOCK, NULL, &sig_mask);
	dump_sigmask("thr2", &sig_mask);

	system("echo thr2 is spawn $$ ; sleep 17");

	sleep(3);
}



int
main(int argc, char *argv[])
{
int status=0;
int fd;
pthread_t child[2];
sigset_t sig_mask ;

	sigfillset(&sig_mask);
	if (sigprocmask(SIG_BLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
/*
	sigaddset(&sig_mask, DF_INITIAL_MASK) ;
	if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL)) {
		perror ("main(): Dead set...");
	}
*/
//	register_handler();

	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);



/* スレッド生成 */
	pthread_create(&child[0], NULL, thr1, NULL );
	pthread_create(&child[1], NULL, thr2, NULL );

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigemptyset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	

#if (DF_CHGMASK_ID==0)
	sigfillset(&sig_mask);
	if (sigprocmask(SIG_SETMASK, &sig_mask, NULL)) {
		perror ("main(): failure set...");
	}
#endif
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	sleep(4);	
	if (sigprocmask(SIG_UNBLOCK, NULL, &sig_mask)) {
		perror ("main(): Dead get...");
	}
	dump_sigmask("main", &sig_mask);

	status = pthread_join(child[0], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
	status = pthread_join(child[1], NULL);
	if (status<0) {
		printf("pthread_join(0) returns: %d\n", status);
	}
return 0;
}

2013/01/08(火)sigactionを触ってみる。

backtraceを取れるか確認する(PwerPC 32bitでのみ確認)

glibcに、backtrace()函数があって、便利だなぁ、と。
自分で書かなくて良いんだねぇ。組み込みRTOSで触ってた何か、は、スタックを手動で追っていたわ~。
コレも自動化しすぎて、スタックと思ったアドレスが別空間だとSIGSEGVでおちるけどな…
/*
 * sigaction sample program for powerpc32
 *  You can add more informations in segv_handler().
 *  In this fucntion, you have pointer of stacks, regs, contexts...
 *  If we can allow increase size of binary, we can continu using backtrace_symbols()/backtrace_symbols_fd().
 *  Please refer man-pages, info-pages and a lot of WEB-pages B)
 *
 * Author: 30/Aug./2012 YNK
 * NOTE: Don't use '=O2' because optimization makes no 'bl' instructions to call function.
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <execinfo.h>
#include <linux/sysctl.h>
#include <sys/ucontext.h>

int (*func_ptr)() = (void *)0x1234567;
int func1();
int func2();
void segv_handler(int n, siginfo_t *pSigInf, void *pContext);

int main(int argc,char ** argv)
{
struct sigaction sa;

	memset(&sa,0,sizeof(struct sigaction));
	sigemptyset(&sa.sa_mask);
	sa.sa_flags |= SA_SIGINFO ;
	sa.sa_sigaction = segv_handler;
	sigaction(SIGSEGV,&sa,NULL);
	func1();
return 0;
}

int func1()
{
  func2();
return 0;
}

int func2()
{
  *(int*)0xBAD2DEAD = 2;
  func_ptr();
return 0;
}

void segv_handler(int n, siginfo_t *pSigInf, void *pContext)
{
int cnt, i;
void **arr = alloca(256 * sizeof(void *));
ucontext_t* pCon = (ucontext_t *)pContext;

	printf("*** segmentation fault! (No=%d)\n", n);
	printf("  An errno value: %d\n", pSigInf->si_errno );
	printf("  Signal code   : %d\n", pSigInf->si_code );
	printf("  access address  : %p\n", pSigInf->si_addr );

// struct defined in ptrace.h
	for(i=0;i<32;i++) {
		printf("GPRS%2d: 0x%08X\n", i, pCon->uc_mcontext.regs->gpr[i]);
	}
	printf("NIP=0x%08X  MSR=0x%08X\n", pCon->uc_mcontext.regs->nip, pCon->uc_mcontext.regs->msr );

	printf("\n\n *** backtrace address ***\n");
	cnt = backtrace(arr, 256);
	for(i=0;i<cnt;i++) {
		printf("\t%3d: 0x%08X\n", i, arr[i]);
	}
/* if included symbolx(compile with "-r dynamic") */
	backtrace_symbols_fd(arr, cnt, 2);

        abort();
}