Linux kernel uses lot's of sections to modularize it's code structure easily.
In case of kernel module and parameter, following section is used.

[ Module ]
macro   : module_init()
section : device_initcall (section name : .initcall6.init) <see init.h>
[ Parameter ]
macro   : module_param_named(), module_param(), core_param() etc.
section : __param <see moduleparam.h>

core_param() macro works like other module parameter. But this is NOT for module BUT for kernel booting parameter.
Kernel parameter doesn't have any prefix unlike other modules.
Module parameter's name has <module name> as it's prefix.
For example, parameter <param> of module <module> has name <module>.<param>
See source code for details.

KBUILD_MODNAME is preprocessor value for module name.
This is defined through complex script processing. See Makefile.libMakefile.mod* in scripts/.
But in most case, you can know it by intuition. That is,  name that seems like module name, is set as KBUILD_MODNAME.
(ex. <mod name>-y<mod-name>-m in Makefile)
So, usually, deep analysis about above scripts are not required.

Note:
It's possible that one object gets potentially linked into more than one module.
In that case KBUILD_MODNAME will be set to  foo_bar, where foo and bar are the name of the modules.

Module and parameter initialization.

[ Built-in module ]
module initialization : do_initcalls() <see 'main.c'> => initcall section is used
parameter sysfs node  : param_sysfs_init() -> param_sysfs_builtin() => __param section is used
[ Dynamic module ]
module & parameter initialization is done at system call
SYSCALL_DEFINE3(init_module, ...) => load_module()

Each parameter has permission mask. So, parameter value can be read or written at runtime through sysfs node.

/sys/module/<module name>/parameter/<parameter name>

But module parameter whose  permission is 0, is ignored at sysfs (Not shown at sysfs).
( See module_param_sysfs_setup(...) function. )

[ SW 엔지니어에 대한 잘못된 생각들 ]

SW를 잘 알지 못하는 사람들이, SW 엔지니어에 대해 이야기 할때 일반적으로 범하기 쉬운 몇가지 오류들에 대해서 짚어보고자 한다.

* SW엔지니어는 일정을 이야기할때 굉장히 보수적인 일정만을 말한다.

음... 일부러 일정을 늘려서 이야기하는 엔지니어도 분명히 존재한다.
그렇지만, 그런 경우는 엔지니어의 태도문제도 존재하지만, 조직의 분위기에도 문제가 있다고 보는게 옳다.
estimation한 일정을 지키지 못했을 경우 - fix된 일정이 아니라 estimation한 일정임에도 불고하고 - '실패'로 몰아세우면서 질책하는 문화에서는 보수적인 일정을 제시할 수 밖에 없기 때문이다.
이런 '책임 회피성 일정'을 논외로 한다면, 엔지니어들은 일정을 굉장히 aggressive하게 제시하는 경향이 오히려 강하다.
왜냐하면, 일에 대한 구체적인 분석이 없는 상태의 초기 estimation은 항상 여러가지 사항들을 놓치게 마련이고, 따라서 실제 일의 양보다 적은 양을 예상하기 때문이다.
그래서, "실질적인 일정 = 엔지니어의 예상 * 2"라는 우스겟 소리도 있다.
따라서, 필자는, 조직에서 SW엔지니어들이 보수적인 일정을 제시하는 경향이 있다면, 그것이 소위 '책임 회피성 일정'이 아닐까를 먼저 의심하고 그렇게 할 수 밖에 없게 만드는 조직의 문제점을 찾아서 제거할 필요가 있다고 생각한다.

* SW엔지니어의 생산성은 투입된 시간에 비례한다.

SW작업에서 물리적인 시간적 투자를 필요로 하는 일은 일부에 지나지 않는다. 대부분은 고도의 집중력을 요구한다.
대부분의 사람들이 위의 이야기에는 동의함에도 불구하고, SW엔지니어가 일한 시간에 관심을 가지는 이유는, 생산성을 측정할 수 있는 방법을 알지 못하기 때문이다.
그렇기 때문에 '시간 투자 = 성실/성과' 이라는 차선(?)책을 사용하고 있고, 이것이 생산성과 시간과의 관계에 대한 잘못된 생각을 퍼트리고 있다.

* 많은 버그를 잡는 사람은 뛰어난 SW엔지니어이다.

버그는, 수정하는게 중요한게 아니고, 만들지 않는 것이 중요하다.
이는 비단 초기 개발 단계만의 이야기가 아니다. 버그를 잡기 위해서 다시 버그를 만드는 과정을 반복하는 많은 미숙한 엔지니어들이 있다.
만약, 실제로 SW를 개발을 하는 팀이라면, 버그에 관계된 성과 측정기준은, 반드시 "발견된 버그의 개수"가 되어야기 "수정한 버그의 개수"가 되어서는 안된다.
이는 유지보수팀에서도 일정부분 적용되는데, 유지보수팀에서는 "버그를 수정한 수"에 앞서 "fix-on-fix"의 수에 더 많은 가중치를 주어야 할 것이다.
넘치는 fix-on-fix를 감당하지 못해서 commit자체를 revert하는 경우도 심심치 않게 일어난다.

* 디버깅을 잘하는 사람은 programming도 잘 한다.

'만류귀종'이라는 말처럼, 궁극에 이르면 두 가지 능력 모두 최고 수준을 보일 것이다.
그렇지만, 상당부분에서 디버깅과 programming은 서로 다른 skill을 요구한다.
필자의 post 중 여기 를 참조하자.

* 작성한 코드의 line수와 생산성은 비례한다.

정말 이 말을 맏는가?
무관하다고 말할 수도 없지만 - 1년에 1라인을 작성한 사람과 하루에 1000라인을 작성한 사람 - 그렇다고 해서 비례하지도 않는다.
너무 극단적인 경우를 제외하고는, 이것은 성과측정의 기준이 될 수 없다.

* 변수/함수의 이름을 바꾸기, 하나의 함수를 두개로 분리하기, compiler warning을 제거하기, 주석 추가/수정하기 등 실질적으로 코드의 동작과 무관한 contribute는 무의미하다.

이런 일들이 생산성과 무관하다고 생각하는 사람이 있다면, 음... 더 이상 필자의 글을 읽을 필요가 없다.
왜냐하면, 기본적인 믿음 자체가 다르기 때문이다.
필자가 보기에는, 이런 일들은 버그를 잡거나, 새로운 기능을 구현하는 것만큼 중요하다.
SW의 가독성을 높여서, 유지보수를 쉽게 하고, SW의 장기적인 건전성을 확보하는 일은 그리 가벼이 볼 일이 아니다.

* 뛰어난 SW 엔지니어는, 버그 및 수정 요구사항을 빠르게 해결해서 적용한다.

'속도'가 중요한게 아니다.
지나치게 빠르다고 생각되는 대부분의 수정은 다량의 'fix-on-fix'를 유발하는 경우가 많다.
'얼마나 빨리 하느냐?' 가 아니라, '얼마나 정확히 잘 하느냐?'가 중요하다.
빨리 했지만 결국에는 버려야 할 contribute보다는, 조금 늦게 진행되고 있지만 착실한 contribute가 가치가 있는 법이다.

기타 많은 것들이 더 있겠지만.. 일단 여기까지만... 생각나면 더 추가하도록 하겠다..

To test Android kernel, keeping minimum number of user space process is very useful.
Actually, 'adbd' and 'ueventd' is enough on Android.
Here is the way how to make device have only minimum user space processes - adbd and ueventd.
Followings are file structure of ramdisk image.

[ Create ramdisk ]

let's make following directory structure in ramdisk.

/bin -> sbin
/sbin -+- busybox
       +- adbd
       +- ueventd -> ../init
       +- <...> -> busybox
/init
/init.rc
/default.prop

All are same with default android except that busybox is in /sbin and /bin is symbolic link to /sbin.
Let's look into one by one.

/init : same binary with default Android.
/bin : symbolic link to /sbin.
/default.prop : same with default Android. - adb and debugging is enabled.
/sbin/busybox : statically linked busybox.
/sbin/... : tools (symbolic link to busybox). Ex, sh -> busyboxls -> busybox.
/sbin/adbd :
Modified adbd. Original adbd uses /system/bin/sh as its terminal shell. But, this one uses /bin/sh.
To do this, value of SHELL_COMMAND at system/core/adb/service.c should be modified.
/init.rc :
Simplified one. Only adbd and ueventd is started.
One important note is, "DO NOT make empty section(ex. on fs)!". This will lead init process to error and system will restarted again and again.
Here is sample.

on early-init
    start ueventd

on init
    sysclktz 0
    export PATH /bin:/sbin:

#on fs

#on post-fs

#on post-fs-data

on boot
   start adbd

## Daemon processes to be run by init.
##
service ueventd /sbin/ueventd

service adbd /sbin/adbd

[ Make ramdisk image ]

Let's assume that current working directory is ramdisk directory.

find . | cpio -o -H newc | gzip > newramdisk.gz

This newly generated gzip file can be renamed directly to ramdisk.img.

[ Make boot image ]

mkbootimg tool is used. This can be easily found at out/host/<arch>/bin after building android from source.

mkbootimg --cmdline 'no_console_suspend=1 console=null' --kernel <zImage file> --ramdisk <ramdisk image> -o newboot

[ Verify ]

After flashing newly generated boot image, reboot device.
The only respond that device can do, is done at boot-loader stage. After that device doesn't anything.
After waiting some moments, try adb device. Then host PC can find the device and adb shell can be used.
Type adb shell ps. Then, you can check that only three user space process are running - initadbd and ueventd.

[ Debugging ]

Except for kernel, adbd and init may be required to be modified (As mentioned above, modified adbd is used.). Printing log is very helpful for debugging and using framebuffer console is simple way to do this.
Here is the step (ex. adbd).

* comment out xxxx in init.c
=> this removes /dev/console (framebuffer console)
* modify start_logging() and start_device_log() in adb.c.
=> use /dev/console as stdout and stderr file.

Now, log message of adbd will be shown on the framebuffer (that is, displayed at the panel.)

[ Something more ]

You may build your own Linux environment on the device by building file system and installing libraries etc.
In my case, I set up tools for development - ex. glibc, gcc, binutils etc, and compiled LTP(Linux Test Project) to test kernel.
Enjoy your minimum Android environment :-).

* SW 엔지니어에 대한 역량 측정의 어려움 *

SW 엔지니어에 대한 역량 측정이 그렇게 중요하다면, 왜 지금까지 이런 것들이 잘 이루어지고 있지 않는 것인가?
아니, 그전에 "제대로 이루어지지 않고 있다."라는 필자의 주장에 대한 근거를 먼저 제시하고자 한다.

SW 개발비용산출시 많이 사용되는 단위가 MM(man-month)이다.
이는, "얼마나 많은 '사람'이 얼마간의 '시간'에 걸쳐 해야 하는 일인가?"를 나타낸다.
이런 방식의 측정은 개인간의 생산성 편차가 작으면 작을 수록 신뢰도가 올라간다.
단순 반복 노동같은 경우,어느 정도 신뢰도 있는 결과를 보여줄 수도 있을 것 같다.
그렇지만, SW programming의 경우, 개인간의 편차가 상당히 크다.
여러 연구 결과가 이를 잘 말해주고 있으니, 특별히 첨언하지는 않겠다.
그런데, 실제 비용산출시에는 MM을 쓴다.
또 다른 근거로는, SW 분야에서, 채용시 지원자의 처우는 대부분의 경우, 전 직장에서의 처우/연봉 + 그 사람의 경력에 의해 결정된다는 점을 들 수 있다.
만약 어떤 방법을 통해서 그 실력을 검증할 수 있다면, 위의 조건들이 지원자의 처우를 결정하지는 못할 것이다.

그렇다면 왜 아직도 이런 문제점이 해결되지 않고 있는가?
SW 엔지니어의 역량을 사회적인 합의가 이루어진 척도를 통해서 수치화 시키는 것이 상당히 어렵기 때문이다 - 사실 불가능에 가깝다.
이제부터 왜 그런지 하나씩 살펴보자.

* SW분야는 일정 수준이 넘어서면, 철학적인 문제를 상당 수 동반하게 된다. 따라서, '정답'이 없는 경우가 많다.

C 언어의 syntax에 대한 문제는 '답'이 있다.
즉, '틀렸다' 혹은 '맞았다'를 말할 수 있다.
그렇지만, C언으로 어떤 방대한 크기의 SW를 만든는 경우, SW layering, architecture design 등에는 정답이 없다.
요구사항에 대한 이해의 정도, 개인의 SW design철학/경험 그리고 속해있는 조직/분야의 culture 등에 따라 다양한 형태의 결과물이 나올 수 있고, "어떤 것이 더 낫다 ."라고 명백하게 판단할 수 없는 경우가 대부분이다.
구체적인 예를 들어보자.
Unix culture는 "정상적인 동작에 대해서는 어떠한 feedback도 주지 않는다." 라는 부분이 있다.
그렇지만, MS Windows의 경우는 "현재 어떤 일이 일어나고 있는지 feedback을 주어야 한다."는 culture가 있는 듯 하다 [*1].
어떤 것이 더 좋은가?
정답이 없다. 각각 장,단점이 존재하고 이러한 장,단점 역시 논쟁의 소지가 충분하다.
물론, 위와 같은 고 수준의 문제가 아니라면 대부분의 전문가들이 동의하는 방법론이 존재하는 것이 사실이다.
그렇지만, 이런 방법론 역시 절대적인 것이 아니기 때문에, 제시된 해결책을 받아들이지 않는다고해서 논리적으로 "당신이 틀렸다."라고 설득할 수 있는 방법은 존재하지 않는다.
이렇게 '정답'이 없는 기술에 대한 역량 측정이 쉬울 리가 없다.

* 좋은 SW의 가치가 실질적인 형태로 나타나기까지는 시간이 걸린다 .

SW life cycle에서 maintenance는 압도적인 비중을 차지한다.
그래서, 좋은 SW design/coding의 방법론을 이야기할 때 maintenance비용에 대한 부분이 항상 언급된다.
그런데,  "maintenance의 비용을 줄이기 위해 많은 노력과 고민을 통해서 SW를 design하고 구현한 결과물"과, 소위 말하는 "당장 돌아가만 가는 결과물" 두 가지에 대한 차이를, 기술적인 지식이 부족한 의사결정권자들이  구별해 내는 것은 불가능에 가깝다.
위에서 언급한 두 가지 SW 결과물의 차이가 실질적인 '비용'의 형태로 나타나는 것은, 개발과 maintenance가 같은 사람/팀에 의해 최소한 2~3년이상 이루어졌을때 부터이다.
그리고, 그 이후에는 차이가 기하급수적으로 벌어진다. 그렇지만 이 말은, 기술적인 분석을 제외한 상태에서, 좋은 SW와 나쁜 SW를 구별하기 위해서는 2~3년의 시간이 필요하다는 뜻이기도 하다.
물론, 기술적인 분석 자체도 상당한 시간을 요구한다.
이런 SW의 특성은, 단기간내에 금전적인 가치로 환산된, 수치화 된 결과물을 바라는 국내 산업환경과 대치된다.

* 기술적으로 뛰어난 사람이라 하더라도, 엔지니어의 실력을 평가하는데 오랜 시간을 필요로 한다.

각종 오디션을 생각해 보자. 노래, 춤, 연기 등등.
그런데, 'SW programming 오디션' 이라는 말을 들어본 적이 있는가?
(Programming 대회를 말하고 있는 것이 아니다.)
없을 것이다. 노래/춤 같은 오디션은 처음 몇 초만을 보고도 미숙한 지원자의 상당 수를 걸러 낼 수가 있다.
그렇기 때문에, 하루에 수백명의 오디션을 볼 수가 있는 것이다.
그렇지만, SW의 경우는 다르다.
노래/춤의 오디션에서 자격 미달의 미숙한 지원자를 찾아내기 위한 '몇 초'는, SW 엔지니어의 면접에서는 '몇 십분'에 해당한다. 이런 상황에서 어떻게 많은 수의 엔지니어를 충분히 평가할 수 있겠는가?
그리고, 어차피 충분히 평가할 수 없다는 것을 알고 있기 때문에, 평가자 역시 일정 수준이상의 노력은 사용하지 않는 것 같다.

* SW에는 다양한 분야가 존재한다.

비록 SW라는 이름으로 통합되어 있지만, SW는 다양한 분야로 이루어져 있다. 그리고 각 분야가 필요로 하는 기술적인 지식 또한 다양하다. 이런 점을 반영하기 위해서, SW 엔지니어의 기술적인 역량을 이야기 할때, domain knowledge를 같이 이야기 하게 된다. 예를 들면, Java Application SW, System SW 등등이 있겠다.
업무 영역 또한 다양하다. Integration, Programming, Debugging, Porting 등의 분야가 있고, 각 분야에서는 요구하는 skill set에는 어느 정도 차이가 있다. 그렇기 때문에,  programming은 정말 잘 하지만, 다른 사람의 code를 debugging하는 능력은 평범한 사람이 있고, 반대로 programming skill자체는 평범하지만, debugging에는 뛰어난 성과를 보이는 사람도 존재한다.
이런 다양한 가치들을 고려한 측정기준을 만드는 것은 결코 쉬운일이 아니다.

이외에도 많은 이유들을 들 수 있겠지만, 일단 이 정도만 이야기 하도록 하겠다.

[*1]
이 부분에 대해서는, 특별히 어디에 명시적으로 언급되어 있질 않아서 100%확신할 수는 없지만, 대부분의 Windows program이 일어나고 있는 일들에 대해서 feedback을 준다.
예를 들면, Unix에서 "rm -rf ."는 정상적으로 동작한다면, 끝날때 까지 아무런 feedback도 주지 않는다.
그렇지만 Windows의 경우, 어느 정도 진행되고 있는지 progress bar의 형태로 보여주는 것이 일반적이다.

Check 'Requesting program interpreter' in 'Program Headers' section of ELF.
Simple command : readelf -l <file>

OOP SW design is usually compose of one main control routine (henceforth MCR) and lots of sub modules.
But, MCR don't need to (must not need to) know inside implementation of every sub modules.
Sometimes, MCR don't need to know even existence of some sub modules.
The problem is, most sub modules require initialization.
How can sub modules whose existence is now known, be initialized.
Due to this issue, principle of information hiding is sometimes broken.
Let's see below example.

FILE : main.c
-------------
int main(int argc, char* argv[]) {
        ...

}

FILE : moduleA.c
----------------
...

FILE : moduleB.c
----------------
...

Assume that, each module requires initialization and main.c don't need to know existence of each module.
How can we resolve this issue?
Easiest way is calling initialization function of each module with damaging principle of information hiding little bit, like mentioned above.

FILE : main.c
-------------
extern void moduleA_init();
extern void moduleB_init();

int main(int argc, char* argv[]) {
        ...
        moduleA_init();
        moduleB_init();
        ...
}

FILE : moduleA.c
----------------
...
void moduleA_init() { ... }

FILE : moduleB.c
----------------
...
void moduleB_init() { ... }

At above code, main.c becomes to know existence of moduleA and moduleB.
That is, in terms of modules, principle of information hiding is damaged although it's very little.
Additionally, global symbol space is dirtier.
Regarding maintenance, whenever new module is added, modifying main.c is unavoidable.
But, main.c doesn't have any dependency on newly added module.
With this and that, this way is uncomfortable.
How can we clean up these?
Using constructor leads us to better way.

Functions in constructor are executed before main function.
So, it is very useful for this case.
Easiest way is setting every initialization function as constructor.
But, in this case, we cannot control the moment when module is initialized at.
Therefore, it is better that each module's initialization function is registered to MCR, and MCR calls these registered function at right moment.
Following pseudo code is simple implementation of this concept.

FILE : main.c
-------------
void register_initfn(void (*fn)()) {
        list_add(initfn_list, fn);
}

int main(int argc, char* argv[]) {
        ...
        /* initialize modules */
        foreach(initfn_list, fn)
                (*fn)();
        ...
}

FILE : module.h
---------------
extern void register_initfn(void (*fn)());
#define MODULE_INITFN(fn)                               \
        static void __##fn##__() __attribute__ ((constructor)); \
        static void __##fn##__() { register_initfn(&fn); }

FILE : moduleA.c
----------------
...
#include "module.h"
...
static void _myinit() { ... }
MODULE_INITFN(_myinit)

FILE : moduleB.c
----------------
...
#include "module.h"
...
static void _myinit() { ... }
MODULE_INITFN(_myinit)

Now, MCR don't need to know existence of each modules.
And, MCR can also control the moment of each module's initialization.
In addition, adding new module doesn't require any modification of MCR side.
It is closer to OOP's concept, isn't it?

We can improve this concept by customizing memory section.
Here is rough description of this.

* Declare special memory section for initializer function.
    - In gcc, ld script should be modified.

* Put initializer function into this section.
    - __attribute__ ((__section__("xxxx"))) can be used.

* MCR can read this section and call these functions at appropriate moment.

Actually, this way is better than using constructor in terms of SW design.
Linux kernel uses this concept in it's driver model.
(For deeper analysis, kernel source code can be good reference.)
But, in many cases, using this concept may lead to over-engineering.
So, if there isn't any other concern, using constructor is enough.

Separating mechanism from policy is very important issue of SW design.
This is also true for microscopic area - implementing function.
Here is one of simplest example - function that calculates area of rectangle.

int rect_area(int left, int top, int right, int bottom) {
        return (right - left) * (bottom - top);
}

Simple, isn't it?
But, this function doesn't have any exception/error handling.
Let's add some of them.

int rect_area(int left, int top, int right, int bottom) {
        if (left >= right)
                left = right;
        if (top >= bottom)
                top = bottom;
        return (right - left) * (bottom - top);
}

It's seems good.
Soon after, another function that calculates area of rectangle is needed.
But, this function should return error value if input rectangle is invalid.
I think quick solution is

int rect_area2(int left, int top, int right, int bottom) {
        if (left > right || top > bottom)
                return -1;
        return (right - left) * (bottom - top);
}

But, in this solution, code for calculating area of rectangle is duplicated.
At above example, this is just one-line code. So, duplicating is not a big deal.
But, it's not good in terms of code structure.
Why did this happen?
Calculating rectangle area is 'Mechanism'.
But, exception/error handling is 'Policy' at this example.
So, above example should be implemented like below.

static inline int _rect_area(int left, int top, int right, int bottom) {
        return (right - left) * (bottom - top);
}

int rect_area(int left, int top, int right, int bottom) {
        if (left >= right)
                left = right;
        if (top >= bottom)
                top = bottom;
        return _rect_area(left, top, right, bottom);
}
int rect_area2(int left, int top, int right, int bottom) {
        if (left > right || top > bottom)
                return -1;
        return _rect_area(left, top, right, bottom);
}

Can you know the difference?
'_rect_area' is implementation of pure 'Mechanism'.
And policy is implemented at each interface function.
Even for simple function, developer should consider CONCEPT of separating Mechanism from Policy.

This test is done under following environment.

x86 :

intel Core(TM)2 Duo T9400 2.53Mhz
GCC-4.4.5

ARM :

OMAP4430 (Cortax-A9)
Android NDK platform 9

Test code.

/*
 * Test Configuration
 */
#define _ARRSZ    1024*1024*8

static int _arr[_ARRSZ];

static void
_init() {
    int i;
    for (i = 0; i < _ARRSZ; i++)
        _arr[i] = i;
}

static unsigned long long
_utime() {
    struct timeval tv;
    if (gettimeofday(&tv, NULL))
        assert(0);
    return (unsigned long long)(tv.tv_sec * 1000000)
        + (unsigned long long)tv.tv_usec;
}

#define _test_arraycopy_pre()               \
    int  i;                                 \
    unsigned long long ut;                  \
    int* ia = malloc(_ARRSZ * sizeof(*ia));

#define _test_arraycopy_post()              \
    free(ia);

#define _operation()            \
    do {                        \
        ia[i] = _arr[i];        \
    } while (0)

static void*
_test_arraycopy_worker(void* arg) {
    int     i;
    int*    ia = arg;
    for (i = (_ARRSZ / 2); i < _ARRSZ; i++)
        _operation();
    return NULL;
}

static unsigned long long
_test_arraycopy_sc() {
    _test_arraycopy_pre();

    ut = _utime();
    for (i = 0; i < _ARRSZ; i++)
        _operation();
    ut = _utime() - ut;

    _test_arraycopy_post();

    return ut;
}

static unsigned long long
_test_arraycopy_dc() {
    pthread_t thd;
    void*     ret;
    _test_arraycopy_pre();

    ut = _utime();
    if (pthread_create(&thd,
               NULL,
               &_test_arraycopy_worker,
               (void*)ia))
        assert(0);

    for (i = 0; i < (_ARRSZ / 2); i++)
        _operation();

    if (pthread_join(thd, &ret))
        assert(0);

    ut = _utime() - ut;

    _test_arraycopy_post();

    return ut;
}

#undef _test_arraycopy_pre
#undef _test_arraycopy_post

int
main(int argc, char* argv[]) {
    _init();
    printf(">> SC : %lld ", _test_arraycopy_sc());
    printf(">> DC : %lld\n", _test_arraycopy_dc());
    return 0;
}

[Test 1]
x86

>> SC : 59346 >> DC : 38566
>> SC : 59195 >> DC : 39028
>> SC : 49529 >> DC : 38160
>> SC : 49722 >> DC : 38457
>> SC : 49952 >> DC : 37457

ARM

>> SC : 102295 >> DC : 94147
>> SC : 102264 >> DC : 94025
>> SC : 102173 >> DC : 94116
>> SC : 102172 >> DC : 94116
>> SC : 102325 >> DC : 94177

Change '_operation' macro to as follows

#define _operation()                                    \
    do {                                                \
        if (i > _ARRSZ / 2)                             \
            ia[i] = (_arr[i] & 0xff) << 8 ^ _arr[i];    \
        else                                            \
            ia[i] = (_arr[i] & 0xff) << 16 ^ _arr[i];   \
    } while (0)                                         \

[Test 2]
x86

>> SC : 60696 >> DC : 40523
>> SC : 56907 >> DC : 45355
>> SC : 55066 >> DC : 42329
>> SC : 54931 >> DC : 40651
>> SC : 57022 >> DC : 41879

ARM

>> SC : 164514 >> DC : 112671
>> SC : 163971 >> DC : 112854
>> SC : 164521 >> DC : 112976
>> SC : 163940 >> DC : 112732
>> SC : 164245 >> DC : 112671

Interesting result, isn't it?
For heavily-memory-accessing-code (Test 1), ARM does not show good statistics for multi-core (in this case, dual-core) optimization.
But, if not (Test 2), optimization shows quite good results.
And, x86 seems to handle memory accessing from multi-core, quite well.

So, developers should consider ARM's characteristic when optimize codes for multi-core.
(I'm sure that ARM will improve this someday! :-) )

* Things to consider regarding this kind of optimization *
Cache, Cache coherence, Memory Controller, Bus etc...

[ Test for later version of ARM (ex Cortax-A15) will be listed continuously... ]

'Domain > ARM' 카테고리의 다른 글

[ARM] Sample code for unwinding stack with DWARF2 information.  (0) 2010.04.07
[ARM] Sample code for unwinding stack in Thumb mode.  (0) 2010.04.07
[ARM] Unwinding Stack.  (0) 2009.09.15
[ARM] Long jump.  (0) 2007.06.05
[ARM] .init_array section  (0) 2007.03.18

Service
-------
init process 는 다음을 통해서 각종 service를 control함.

SIGCHLD signal handler를 정의해서, service의 상태를 파악함
service가 죽는 경우 SIGCHLD signal이 날아오고, 이 signal로 어떤 service가 죽었는지/시작했는지 파악하고, 각 service의 flag에 따라서 다음 행동 (해당 service를 다시 시작하거나, system을 restart하거나 (critical service))을 결정함.
[property_service.c] '/dev/socket/property_service' socket을 열고 message를 기다림 (PROP_SERVICE_NAME).
'property_set(...)' interface를 통해서, property_service socket에 message가 써지고, init process의 property service부분에서 이 message를 handling함.
'ctl.start/stop/restart' 는 source code에 hard-coded된 특수한 message로, 해당 이름의 service를 control한다.

잊어먹지 않기 위해서 일단 기록해 둠....

* 들어가는 글. *

SW 엔지니어로 다년간을 보내면서, 많은 불합리/부조리 를 보아왔다.
그리고, 이런 문제들이 어디서부터 비롯되었는지를 고민해 왔었다.
나 뿐만이 아니라 이 바닥 (SW Engineering)에서 밥을 빌어 먹고 있는 사람들이라면, 누구나 한번쯤은 이런 고민을 해 보았으리라 생각된다.
그리고 나름대로 고민한 내용들을 기록해 두는 것도 의미가 있는 일이라고 생각되어서 "SW 엔지니어 역량 측정"이라는 카테고리로 글을 시작하고자 한다.
이 글은 어떠한 과학적 근거나, 의미있는 실험적인 통계에 바탕을 두거나 하지 않은다.
말 그대로 나의 상상의 나래에서 뻗어나온 생각의 줄기일 뿐이다.
그리니 괜시리 딴지 걸지 말자... -_-; 그냥 한 blogger의 humble opinion일 뿐이니까...

* 왜 MMORPG 게임은 재미있는가? *

뜬금없이 MMORPG로 이야기를 시작하고자 한다.
리니지, WOW, 던파 등등 한국은 MMORPG게임의 천국이다.
몇몇 콘솔 게임을 제외한 패키지 게임 시장은 고난의 나날을 보내 있음에도, MMORPG 시장은 끝없이 성장하고 있다.
왜냐고? 재미있으니까...
불법 복제 문제를 뒤로 하고서라도, MMORPG가 재미있고 중독성이 강하다는 것은 부정하기 힘들다.
그럼 왜 MMORPG는 재미있는가?
여러가지 이유가 있을 수 있겠지만, 난 아래와 같은 내용에 주목하고자 한다.

* 소위 '레벨'로 대변되는 "모든 사람이 동의하는 역량의 기준"이 존재한다.
* '레벨'은 알기 쉽고 비교하기 쉽게 수치화 되어 있다.
* '레벨'은, 모두 평등한 조건에서 시작하고, 노력한 만큼 얻는다.
* '레벨'이 높은 캐릭터는 거기에 따른 대우/보상 - 게임상에서의 지위, 게임 머니 등등 - 을 받는다.

독자가 여기에 동의하지 않는다면... 음 할수 없다. (-_-;) 그냥 동의하는 '척' 해 주길 바란다.
각설하고, 한 마디로 요약하면, "열심히 하면 누구에게나 인정받고 최고가 될 수 있다." 라는 뜻이다.
현실 세계가 위와 같은 조건을 가진다고 가정해 보자.
그리고, '대우/보상'은 현실세계를 반영해서 '돈'이라고 가정해도 좋다.
그러면 당신은 어떤 선택을 하겠는가?
그래도 MMORPG를 하고 있겠는가? 아니면, 현실세계에서 열심히 '레벨 업'을 할 것인가?
나라면 후자를 택할 것이다.
돈을 많이 버는 사람은 그 만큼 레벨도 높은 사람이고, 그 사람은 레벨을 높이기 위해서 다른 사람보다 더 많이 노력한 사람이다.
따라서, "더 많은 돈을 받을 가치가 있다."는 사회적인 동의를 쉽게 얻을 수 있다.
어떤가? 얼마나 재미있는 사회인가?
기타 여러가지 외적인 요소는 일단 무시하자 - 딴지 걸지 말라는 뜻이다. (-_-)

왜 갑자기 이런 이야기를 꺼내는 걸까?
SW Engineering분야에서 생기는 많은 문제점들이 이와 관련되어 있기 때문이다.
인사(人事)분야에 올인 해서 생각을 해보자.
사실, 인사분야만 해결되면 나머지는 거져 먹는 거다. (인사(人事)는 만사(萬事) 니까...)

현재 국내 SW 업계를 보면, 회사는 뽑을 사람이 없다고 난리고, 엔지니어들은 갈 곳이 없다고 외친다.
뽑을 사람이 없다는 것은, 필요한 사람을 원하는 가격에 채용할 수 없다는 뜻이다.
갈 곳이 없다는 것은,  원하는 수준으로 대우를 해 주는 회사를 찾을 수 없다는 말이다.
자, 이제 모든 SW 엔지니어의 머리위에 그들의 실력을 나타내는 '레벨' 막대가 있다고 생각해보자.
그럼 회사는 소위 '뽑을 사람'을 쉽게 결정할 수 있다.
자금에 여유가 있다면, 실력좋은 사람을 그 만한 대우를 해 주고 데려 오면 되고, 그렇지 않다면, 회사가 제공해 줄 수 있는 수준의 사람을 채용하면 된다.
"어떻게든, 싼 가격에 좋은 사람을 채용하겠다!"
라는 논리가 더 이상 통용될 수 없으니, "뽑을 사람이 없다!"는 말은 "뽑을 (자금적인)여력이 안된다!" 라는 말로 바뀔 수 밖에 없게 된다.
이것은 엔지니어 관점에서도 마찬가지이다.
본인이 어느 정도 수준인지를 쉽게 알 수 있으므로, 본인이 어느 정도의 가치가 있는지도 쉽게 알 수 있다. 따라서,
"어떻게든, 대우가 좋은 곳으로 가겠다!"
는 생각은 통용될 수 없다.
"갈곳이 없다!"라는 말은 "내가 능력이 부족하다!"라는 말로 대체될 수 밖에 없다.
비단 채용뿐만이 아니다.
회사내에서의 승진, 연봉 협상, 대우에 따른 불만 등등이 모두 이와 일맥 상통한다.

그럼, 이런 것들이 현실적으로 가능한가? 물론 불가능 하다. 윗 글은
"사회(혹은 소속 집단)적 동의를 얻은, 측정 기준과 수치화된 결과가 가지는 힘"
에 대한 이야기이며,  엔지니어의 능력을 측정하는 합리적인 metric이 필요한 이유이기도 하다.

+ Recent posts