Short-Circuit Evaluation 은 &&이나 || 에서 첫번째 argument 에서 조건의 결과값에서 이미 전체 결과값이 판단되었을 경우 첫번째로만 수행하는 것을 말한다.


예를 들어,

BOOL condition1(int pValue)
{
    printf("condition1() has been executed\n");
    return 0 == pValue;
}

BOOL condition2(int pValue)
{
    printf("condition2() has been executed\n");
    return 0 == pValue;
}

int main()
{
    int count1 = 1;
    int count2 = 0;

    if (condition1(count1) && condition2(count2))
    {
        printf("&& test\n");
    }

    count1 = 0;
    if (condition1(count1) || condition2(count2))
    {
        printf("|| test\n");
    }
}

첫번째 && 연산에서는 condition1 이 false 이므로 condition2() 까지는 수행 시키지 않는다.

두번째 || 연산에서는 condition1 이 true 이므로 condition2() 까지는 수행 시키지 않는다.


여기까지만 보면 그렇구나 싶긴 한데 골치 아픈건 다음의 경우이다.

static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
{
...
    while (slabp->inuse < cachep->num && batchcount--) {
        STATS_INC_ALLOCED(cachep);
        STATS_INC_ACTIVE(cachep);
        STATS_SET_HIGH(cachep);

        ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
				    node);
    }
    check_slabp(cachep, slabp);
....
}

linux-2.6.24의 커널 코드 중 일부이다.

저기 while 문 안의 경우를 보면 && 연산자는 충분히 Short-Circuit Evaluation 를 할 수 있으며 따라서 2번째 조건인 batchcount--를 수행하지 않을 수도 있다.

물론 리눅스 커널 코드야 저런경우까지 고려해서 작성되었겠지만 Short-Circuit Evaluation을 모르고 막쓰다가 2번째 조건에 뭔가 연산을 일으키지 못한다면 흐름을 이해하지 못하게 될 것이다.


정 헷갈리면 나이브하게 다 풀어서 해야 한다.


Posted by 없다캐라

What is Forced Unit Access (FUA)?

FUA란 write 명령을 직접 스토리지에 사용하는 것을 말하며 디스크 캐시 사용 여부와는 관계 없다.

SCSI T10 스펙에서 처음 나왔으며,  (WRITE DMA FUA EXT – 3Dh, WRITE DMA QUEUED FUA EXT – 3Eh, WRITE MULTIPLE FUA EXT – CEh) 와 같은 SCSI 명령어들이 있다.

FUA는 디스크 미디어에 직접 쓰기가 마무리 되어야 하므로 flush 같은 명령이 떨어지기 전에 파워문제가 발생해도 data에 consistent를 보장할 수 있다.

SCSI에서 나온 스펙이지만 이 후에 ATA T7(2002) 스펙에도 포함 되었다. (이상 위키내용 발췌)


Windows

윈도우즈에서는 Transactional NTFS(이하 TxF)에서 SCSI, Fiber Channel 장비의 경우는 지원한다. 그 외 (ATA/SATA/USB) 에선 지원이 안되기에 power failure 문제에 위험성을 가지고 있기에 캐시 disable 같은 다른 대안을 사용해야 한다.

Disk Cache Disabling

디스크 장치에 대한 cache disable을 하기 위해서는 DeviceIOControl 의 아래 code를 사용하여 정할 수 있다.

MSDN의 Querying for the Write Cache Property 에서 살펴볼 수 있다.

ATA 스펙에 FUA가 포함되었지만 그것이 제대로 구현되었는지 gurantee 되지 않아서 Windows 에서는 채용하지 않았으며 SATA 같은 디스크에서 지원하지 않는다.

NTFS에서는 SCSI 경우 meta data의 integrity를 지켜주기 위해 FUA가 사용된다. 그 외의 데이터 영역이 FUA 사용에 대한 것은 기능이 support 된다고 하는데 어떻게 사용하는지는 확인 할 수 없다.

Transactional 이란 용어에서 meta를 의식한 표현으로 짐작되며 meta는 확실히 FUA를 쓴다고는 하는데 data 부분에 대한 write는 못찾겠다.

그리고 MSDN에서는 TxF를 대체할 수 있는 방법을 찾으라고 강력하게 권장하는데 TxF의 API들이 강력하지만 복잡해서 deprecating시키는 것을 고려중이기에 다른 시나리오를 권고하고 있다. (Alternatives to using Transactional NTFS)

TxF에서 FUA 사용한다는데 TxF를 안쓰면??? 거기까진 언급되지 않아서 모르겠다.

하지만, Windows 8, Windows Server 2012 부터는 metadata에 대한 FUA를 사용하지 않고 대신 캐시를 사용하여 바로 flush 시키는 방식으로 변경하였다고 한다.

그 내용은 Windows Server 2012 64TB NTFS Volumes and the Flush Command 와 Windows Server 2012 64TB NTFS Volumes and the Flush Command 문서에서 확인할 수 있다.

 

FUA 구현을 직접적으로 하기 위해서는 User layer에서는 FILE_FLAG_NO_BUFFERING와 FILE_FLAG_WRITE_THROUGH 플래그가 있는 write를 구현하면 된다.

커널 드라이버에서는 file system, volume 단에서는 IRP_MJ_WRITE의 IRP Stack Location의 Flags에서  SL_WRITE_THROUGH | SL_FT_SEQUENTIAL_WRITE 을 추가시켜주면 된다.

SL_WRITE_THROUGH 은 밑의 linux에서 request io의 REQ_FUA와 같은 거라고 보여진다.

SL_FT_SEQUENTIAL_WRITE은 FT에서 사용하는 값 같은데 정확히 무엇인지는 모르겠다(OSR 참조). 다만, 2개를 같이 묶어서 사용하는 것 같다.

Linux

리눅스에서는 이런 FUA가 block layer lever에서 지원 된다.

SATA 같은 경우는 2007년 즈음 Linux가 NCQ를 지원했고 이런 SATA/NCQ 에 대한 FUA 기능은 2012까지는 안되었다.

리눅스 커널 코드에서는

#define REQ_FUA         (1ULL << __REQ_FUA)

file system 단에서는 bio의 r/w flag에 매스킹 시켜 FUA를 요청할 수 있으며 실 구현은 block device 밑단에서 FUA 관련 기능이 구현되어 있다.

물론 이것은 FUA가 지원되는 device에 한하며 그렇지 못한 경우는  Linux 3.14 kernel document 중 writeback_cache_control.txt 를 보면 마지막에 

bq. If the FUA bit is not natively supported the block layer turns it into an empty REQ_FLUSH request after the actual write.

write이후 FLUSH를 연이어 요청하여 비슷한 동작을 하게끔 한 것 같다. 물론 거기에 대한 payload를 지불할 만하면....


Reference


'Development > System' 카테고리의 다른 글

FUA (Force Unit Access) 관련  (0) 2015.05.13
Posted by 없다캐라

커널 드라이버에서 EventViewer를 위한 로그 작성

커널 드라이버에서 Event Log를 생성하기 위해서는 

    • 구현부
    • Message 리소스 작성
    • 시스템에 리소스 path 작성

이렇게 3부분을 살펴 보아야 한다.

System Event Log 작성을 위한 코드 작성

아래의 function과 data structure를 사용한다.

Function

Data Structure

IoAllocateErrorLogEntry()으로 IO_ERROR_LOG_PACKET 타입의 메모리를 할당받은 후 적절한 값을 assign 후 IoWriteErrorLogEntry()으로 log를 작성하면 된다. 

개념적으로는 IoFreeErrorLogEntry()이 필요하지만 드라이버에서 이를 직접 호출할 필요는 없다.

IO_ERROR_LOG_PACKET 구조체 값 뒷부분에 필요한 argument들을 연속적으로 넣어주면 된다.

이 구조체 값에는 몇몇 주요한 변수들이 있는데 이는 MSDN 문서를 참고한다.

 

과정은 단순하며 2가지 정도 주의할 점이 있다.

    1. 인자로 사용될 메모리 사이즈
    2. 2byte 문자열을 다룰 경우 IRQL 제한


인자의 사이즈 제한

IO_ERROR_LOG_PACKET 의 instance의 메모리 사이즈는 패킷 헤더 포함 size가 ERROR_LOG_MAXIMUM_SIZE를 넘지 못하며 헤더 패킷 size 48을 빼주면 52글자 정도 밖에는 쓸수 없다.

IoWriteErrorLogEntry passes at most 52 characters?

따라서 mc 파일로 작성된 것 외에 argument로는 52 character 그러니까 대략 104byte 정도 더 추가할 수 있다.

2byte 유니코드 사용으로 인한 IRQL 제한

1byte 문자열을 2byte 문자열로 변환할 때 라이브러리에서 제공해주는 일반적인 함수들은 유니코드 변환에 따른 테이블을 참조한다. 이것으로 인해 IRQL 문제가 발생한다.

참고로 변환에 사용해봤던 함수들은 RtlStringCbLength()swprintf_s() 이며 모두 문제를 일으켰다. (DW-23)

IRQL for RtlStringxxx functions

 

MC파일 작성

EventViewer에 남길 메시지를 별도의 text 리소스 파일로 작성해야 한다.

mvolmsg.mc
MessageID       = 5001
Severity        = Informational
SymbolicName    = MSG_DRIVER_LOAD
Language        = English
Driver is loading successfully.
.
MessageID       = 5002
Severity        = Error
SymbolicName    = MSG_NO_JOB
Language        = English
No Job on %2.
.
MessageID       = 5003
Severity        = Error
SymbolicName    = MSG_FIND_JOB_ERROR
Language        = English
cannot find same job on %2.
.
 
 
...

여기에 대한 좀더 자세한 내용은 Creating the Error Message Text File 을 참조한다.

MC.exe compile

MC.exe는 Visual Studio 설치 폴더 중 별도로 있는 util 이며 이를 찾으려면 Windows 버전에 맞는 곳의 bin 경로에서 찾으면 된다.

(참고로 난 c:\Program Files (x86)\Windows Kits\8.1\bin\x64\) 

mc 파일에 필요한 스트링 내용을 정리한 후 이를 message binary로 만드는 것은 아래의 명령어로 할 수 있다.

mc xxxxmsg.mc

이에 대한 자세한 내용은 Defining Custom Error Types를 참고하면 된다.

이렇게 mc build를 하고 나면

    • xxxxmsg.rc
    • xxxxmsg.h
    • MSG00001.bin

이렇게 3 파일이 생성되며 이를 모두 visual studio 프로젝트에 포함시켜 주면 된다.

출력 메시지 path 지정

드라이버에서 해야 할 작업을 모두 마쳤다면 마지막으로 레지스트리에 출력 메시지 binary의 path를 지정해 주는 일을 추가해 주어야 한다.

message binary의 위치가 지정되지 않았다면 아래처럼 실제 메시지 내용을 EventViewer에 보여주지 못한다.



xxxx.sys 를 빌드하면서 메시지도 포함시켰다면 xxxx.sys의 경로를 레지스트리에 지정해 주어야 하는데

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\EventLog\System\DriverName 경로에 아래의 값을 추가한다. 

(관련내용 : Registering as a Source of Error Messages)

    1. EventMessageFile (REG_EXPAND_SZ)
    2. TypesSupported (REG_DWORD)



이렇게 설정 후 별도의 리붓 없이 EventViewer를 실행시키면


이렇게 메시지가 정상적으로 보여진다.

Reference


Posted by 없다캐라

Source Insight를 아직 버리지 못하는 이유가 몇몇 있지만 그 중에

Visual Studio에서 마우스 4, 5버튼으로 backward, forward 기능이 되도록 하는 것을 찾았다.


이 방법이 없진 않을 텐데 찾기도 애매해서 그냥 쓰다가 드뎌 찾았다.

도저히 외워지지 않는 단축키로는 성에 차지 않아서 구글링으로 마구마구 검색했더니 드뎌 찾았다.


http://visualstudiogallery.msdn.microsoft.com/87fb8c65-d1db-49e9-a068-d62a222a4ae7/view/Reviews




이 기능을 공식적으로 뭐라 불러야 할지 몰랐다. 그리고 마우스의 4, 5 버튼이라는 것도 공식적인 이름 같지는 않지만 

내 맘대로 이렇게 이름 지었다.


여튼 이걸 down 받고 나서 실행하면 visual studio 에 찰싹 달라 붙어서 기능이 동작할 것이다.

vs 2010 부터 기능이 있었나 본데 참 검색하기 애매해서 이제야 발견했다.


그리고 C/C++ 을 다시 사용하니 이런걸 보게 되는군.


이 기능 강추다. 소스 인사이트 써본 사람들은 알꺼임.


이제 Eclipse도 되면 좋을 텐데 누구 아는사람?


Posted by 없다캐라

메모리릭으로 IBM AIX 서버의 웹로직 와스가 내려갔다.

그리고 아래처럼 힙덤프 파일이 쌓였다



이중 phd 파일은 IBM의 HeapAnalyzer 를 사용하여 볼 수 있다.

https://www.ibm.com/developerworks/community/groups/service/html/communityview?communityUuid=4544bafe-c7a2-455f-9d43-eb866ea60091

 ha445.jar

다운받아보면 그냥 jar 파일인데 실행은 아래처럼 시켜주면

java -Xmx1024m -jar ha445.jar

사용해볼 수 있다.


그래서 힙덤프파일을 open 하고 나면 위에처럼 분석하는 진행 화면이 나오고 




이렇게 멋진(?) GUI와 함께 볼수 있다.



이전에 jprofiler 처럼 실시간은 안되지만 이렇게 덤프파일을 할당한 객체를 트리형태로 보여주며 차트형식으로 보여주고

leak suspection 에서의 분석은 유용했다.


여튼 난 이걸로 큰거하나 잡았다. 휴~




참조링크#1,

참조링크#2


Posted by 없다캐라

블로그 이미지
없다캐라

태그목록

공지사항

Yesterday50
Today4
Total182,934

달력

 « |  » 2018.07
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

글 보관함


티스토리 툴바