Topic :
當聲明用於分佈式環境或不同CPU間通信環境的數據struct時,必須考慮機器的字節順序、使用的位域及字節對齊等問題。
Description :
1.比如Intel CPU與68360 CPU,在處理位域及整數時,其在內存存放的“順序”正好相反。
2.在對齊方式下,CPU的運行效率要快得多。
1. Endian
/*
* sample-67_1
*
* This sample shows how to write a program
* that can know CPU's endian and how to translate
* to what you want.
*
* You MUST notice CPU's endian, it may cause some
* unpredictable bug.
*
*/#include<stdio.h>
typedef unsigned int __u32;
/* translate endian */
#define u32toValue(x) (\
(((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
(((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \
(((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \
(((__u32)(x) & (__u32)0xff000000UL) >> 24))/*
* Test host device's endian
* 1 : little-endian
* 0 : big-endian
*/
int test_endian(void)
{
int x = 1;return (*(char*)&x);
}void fix_endian(){
unsigned int x = 1;
printf("this host is %s : \n", test_endian()?"little-endian":"big-endian");
printf("%#x, %d\n", x, x);
printf("translat to %s : \n", test_endian()?"big-endian":"little-endian");
printf("%#x, %d\n", u32toValue(x), u32toValue(x));}
int main(int argc, char* argv[]){
fix_endian();
return 0;
}
2. Data Alignment
/*
* sample-67_2
*
* This sample shows that alignment effective.
* A computer accesses memory a single memory word at a time. As long as
* the memory word size is at least as large as the largest primitive data type
* supported by the computer, aligned accesses will always access a single
* memory word. This may not be true for misaligned data accesses.
*
* This principle is especially important when you write code for porting to multiple
* processors. A misaligned 4-byte data member, which is on an address that is not a
* multiple of four, causes a performance penalty with an 80386 processor and a
* hardware exception with a MIPS RISC processor. In the latter case, although
* the system handles the exception, the performance penalty is significantly greater.
*
* This sample use three structures to figure out the important of alignment.
* These structures have the same structure members, orders in structure, and operations.
* "clock_t start, end" will record cpu clock cycles, we can know alignment effective by them.
*/#include<stdio.h>
#include<time.h>#define LOOP_SIZE 1000*1000*10
/*
* This structure does not align, Using __attribute__ ((packed))
* can ask compiler don't pad this structure. Sometimes this declaration is
* necessary. For example, netwrok header does not wish compiler to add padding
* and broken it's design.
*/
struct NO_PAD_STRU{short s0, s1;
int i0, i1;
char c0, c1;
}__attribute__ ((packed));/*
* This structure aligns by compiler, After compilation the data
* structure will be supplemented with padding bytes to ensure
* a proper alignment for each of its members.
*/
struct COMPILER_PAD_STRU{short s0 ,s1;
int i0, i1;
char c0, c1;};
/*
* This structure aligns by programmer. Programmer has to know
* the word alignment on target device.
*/
struct MY_PAD_STRU{
short s0, s1;
int i0, i1;
char c0, c1;
char PADDING0[2]; // padding by programmer
}__attribute__ ((packed));clock_t start, end;
double cpu_time_used;/* operation with NO_PAD_STRU structure*/
void no_padding(){
int i;
struct NO_PAD_STRU no_pad;printf("This structure is not alignment(no_padding):\n");
printf("sizeof(no_pad) : %d\n", sizeof(no_pad));
start = clock();
for(i = 0; i<LOOP_SIZE; i++){
no_pad.c0 = no_pad.c1 = 0;
no_pad.s0 = no_pad.s1 = 1;
no_pad.i0 = no_pad.i1 = i;
}end = clock();
cpu_time_used = ((double) (end - start)); // get cpu clock time
printf("memory access clock : %.0f\n", cpu_time_used);}
/* operation with COMPILER_PAD_STRU structure*/
void compiler_padding(){
int i;
struct COMPILER_PAD_STRU compiler_pad;printf("This structure is alignment(padding by compiler):\n");
printf("sizeof(compiler_pad) : %d\n", sizeof(compiler_pad));
start = clock();
for(i = 0; i<LOOP_SIZE; i++){
compiler_pad.c0 = compiler_pad.c1 = 0;
compiler_pad.s0 = compiler_pad.s1 = 1;
compiler_pad.i0 = compiler_pad.i1 = i;
}end = clock();
cpu_time_used = ((double) (end - start)); // get cpu clock time
printf("memory access clock : %.0f\n", cpu_time_used);
}/* operation with MY_PAD_STRU structure*/
void programmer_padding(){
int i;
struct MY_PAD_STRU my_pad;printf("This structure is alignment(padding by programmer):\n");
printf("sizeof(my_pad) : %d\n", sizeof(my_pad));
start = clock();
for(i = 0; i<LOOP_SIZE; i++){
my_pad.c0 = my_pad.c1 = 0;
my_pad.s0 = my_pad.s1 = 1;
my_pad.i0 = my_pad.i1 = i;
}end = clock();
cpu_time_used = ((double) (end - start)); // get cpu clock time
printf("memory access clock : %.0f\n", cpu_time_used);
}void show_time(){
no_padding();
compiler_padding();
programmer_padding();}
int main(int argc, char* argv[]){
show_time();
return 0;
}
這個 sample講了一般比較不會注意到的 endian 跟 alignment的部份,事實上 alignment 的處理大部份都是 compiler幫忙做掉了,當然也是可以自己加 padding,只是要先知道 target的 alignment是怎麼安排的。
沒有留言:
張貼留言