8KB 링버퍼를 구성하려면 그만큼의 SRAM을 먼저 확보해야 했다. 문제는 이미 메모리가 넉넉한 상태가 아니었다는 점이다. 버퍼 하나를 추가한다고 끝나는 상황이 아니라, 기존에 사용하던 SRAM을 어디서 얼마나 줄일 수 있는지 다시 확인해야 했다. 결국 몇백 바이트, 1KB라도 더 확보하기 위해 map 파일까지 뒤지는 단계로 들어갔다.SRAM 확보를 위한 map 파일 분석처음에는 소스 코드에서 눈에 띄는 큰 버퍼나 전역 변수부터 줄이면 될 것이라고 생각하기 쉽다. 하지만 실제 메모리 사용량을 확인하려면 링크 결과를 봐야 했다. Codex를 이용해 map 파일과 빌드 산출물을 분석하면서 .data, .bss, FreeRTOS Heap, 태스크 Stack에 어떤 심볼이 얼마나 들어가 있는지 확인했다. 사람이..
충전기에서 OCPP 메시지는 JSON 형식을 사용하고 있고, JSON 생성과 파싱에는 cJSON을 사용하고 있다. JSON 객체를 만들고 해제하는 과정에서는 작은 동적 메모리 할당이 반복된다. 장시간 재부팅 없이 동작해야 하는 충전기에서 이 할당을 시스템 공용 Heap과 그대로 섞어 쓰는 것은 부담이 있었다. 그래서 JSON이 사용하는 메모리를 FreeRTOS Heap과 분리하고, 별도의 고정 RAM 영역을 tinyalloc으로 관리해 왔다. GitHub - thi-ng/tinyalloc: malloc / free replacement for unmanaged, linear memory situations (e.g. WASM, embedded devices...)malloc / free replaceme..
입사한 지 약 8개월이 지났을 무렵, 팀 전체 인원이 퇴사하면서 진행 중이던 프로젝트를 인계받아 계속 개발하게 되었다. 처음부터 가장 신경 쓰였던 부분은 메모리였다. 기존에 사용하던 nRF52 계열 MCU와 비교하면 새로 선정된 STM32G4는 사용할 수 있는 메모리 여유가 크게 줄어든 상태였다. 여기에 Wi-Fi 환경에서 서버와 통신하기 위해 ESP32 모듈을 사용하고, ESP32가 서버에서 전달받은 메시지를 STM32로 넘기면 STM32가 이를 기반으로 충전기 제어와 주요 로직을 수행하는 구조였다. 이후 SECC까지 추가되면서 STM32는 충전기 제어뿐 아니라 ESP32와 SECC 사이의 데이터 파이프라인까지 중간에서 맡게 되었다.┌────────┐ WebSocket / JSON ┌──────..
현재 양산된 펌웨어 SDK는 퇴사한 직원이 작업한 소스이며, 나는 이것을 인수인계 받아 양산 F/U을 진행하고 있었다. SDK의 기본 부트로더를 그대로 사용하고 있었다. 이미 그렇게 사용하고 있었기에 변경은 어려웠고, OTA 구조 역시 내가 원하는 방식이 아닌 듀얼뱅크 구조를 사용하고 있다. 그 당시 Application 소스코드 구조가 너무 엉망인 상태라 SW 구조를 다시 설계해야 하지만 시간이 없는 관계로, 적당선에서 타협하여 모듈 단위로 정리하고 매니저로 관리하는 구조로 급한대로 수정하여 현재까지 사용하고 있다. 그리고 이 부분은 전담하는 팀원에 장기 프로젝트로 시간날 때마다 리팩토링 가능성을 살펴보라고 하였다. 그런데 PnC 기능을 구현함에 있어, STM32G4 칩셋의 메모리 제약사항으로 ESP..
MyGPT를 오래 켜놓고 쓰다 보면 어느 순간부터 시스템이 묘하게 무거워졌다. 처음에는 ChatGPT 웹 자체가 무거운가 보다 하고 넘겼는데, Activity Monitor를 확인해보니 QtWebEngineProcess가 비정상적으로 커지고 있었다. 평소처럼 며칠씩 사용했을 때는 9GB에 육박한 적도 있었고, 이 정도면 단순히 “Chromium 계열이라 원래 많이 먹는다”는 말로 넘기기 어려웠다. 우연인지 확인하려고 일요일부터 MyGPT를 다시 평소처럼 사용했다. 긴 대화방을 오가고 과거 내용을 보기 위해 위로 스크롤하면서 계속 작업했는데, 하루 조금 지난 월요일 저녁에는 QtWebEngineProcess가 이미 3.93GB까지 올라가 있었다. 이번에는 앱을 재시작해서 숫자를 지우지 않고, 실제로 어디에..
앞선 작업에서는 MyStock의 JSON Export 데이터 용량을 줄이는 데 꽤 많은 시간을 썼다. 처음에는 데이터를 많이 넣어두면 LLM이 알아서 필요한 부분을 찾아 쓸 것이라고 생각했고, 그 다음에는 지시문을 더 자세히 적으면 분석 품질이 안정될 것이라고 생각했다. 실제로 여러 모델을 돌려보니 둘 다 절반만 맞는 이야기였다. JSON 안에 데이터가 존재하는 것과 LLM이 그 데이터를 실제 판단에 사용하는 것은 다른 문제였고, 지시문이 길어진다고 실행 결과까지 안정되는 것도 아니었다. 그래서 최신 모델인 아스트라를 이용해 JSON Export 구조를 다시 줄였다. 계좌, 종목, ETF 구성, 시장지표처럼 판단에 필요한 정보는 남기되, 같은 사실을 너무 높은 해상도로 반복해서 전달하는 부분은 줄였다. ..
앞선 실험에서는 MyStock의 투자 데이터를 JSON으로 내보내 여러 LLM에 그대로 던져봤다. 계좌 상태와 손익, 보유 ETF의 가격과 거래량, 투자자 수급, ETF 구성종목과 최근 변화, 실제 기초자산 기준의 중복 노출, 거래내역, 그리고 시장지표의 과거 데이터까지 한 파일에 넣었다. 당시 Pretty JSON은 약 1.28MB까지 커졌는데, 내 계좌 하나를 분석하기 위한 파일이라는 점을 생각해도 1.3MB 정도는 별문제가 아니라고 생각했다. 데이터를 충분히 넣어두면 LLM이 그 안에서 필요한 정보를 알아서 찾아 관계를 연결할 것으로 기대했지만, 실제 결과는 달랐다. 눈에 잘 보이는 현재 수익률이나 보유 비중은 비교적 잘 사용하면서도, 일부러 넣어둔 과거 시장 흐름이나 ETF 구성 변화, 수급처럼 ..
MyStock에 JSON Export를 붙인 이유는 거창하지 않았고, 내가 가진 포트폴리오와 과거 시장 데이터를 한 번에 넘기고, AI(LLM)에게 “오늘 시장환경에서 내 포트폴리오를 어떻게 운용하는 방향이 좋을지” 물어보고 싶었다.계좌 상태, 보유 ETF, 가격과 거래량, 투자자 수급, ETF 구성종목과 최근 변화, 실제 기초자산 중복 노출, 거래내역, 시장지표 3년치를 한 파일에 넣었다. 파일은 약 1.2MB까지 커졌다. 이 정도면 AI가 알아서 필요한 데이터를 찾아서 분석할 거라고 생각했다. 실제로 돌려보니 예상과 달랐고 데이터가 없는 게 아니라, 데이터가 있어도 모델이 굳이 읽지 않았다.첫 번째 실험초기 JSON을 Gemini, Claude, Grok에 전달했다. 별도의 분석 프롬프트를 다시 쓰지..
요즘 퇴근 후, ChatGPT하고 노느라고 집에서 PC 사용이 부쩍 늘어나, 인터넷이 간헐적으로 끊기는 상태를 즉각 느낄수 있었다. 예전에 사용한 무선 공유기 ipTIME은 이럴 때마다 재부팅 한번으로 해결되긴 했는데, 천장형 AP는 살펴보니 전원공급 어댑터 연결이 없는 것이 아닌가? 그래서 신발장 네트워크 단자함을 열어 일단 라우터를 재부팅하였으나, 여전히 천장형 무선 공유기 AP1100은 동작하지 않았다. 여기서부터 오늘 사건의 시작이었다. 여전히 AP가 동작하지 않아 디오넷 AP1100 모델 전면부에 리셋 버튼을 실행하였는데, 예상치 못한 결과가 발생하였다.이상한 초기화리셋으로 인해 기존에 설정한 SSID가 삭제된 것은 예상범위였고, WIFI_2G / WIFI_5G 추가되고 비밀번호 없이 사용이 가..
MyStock의 DB 작업이 어느 정도 마무리되고 투자기록까지 실제 데이터와 연결되면서 프로그램의 기본적인 뼈대는 꽤 많이 갖춰졌다. 처음에는 데이터를 가져와 화면에 보여주는 것이 중요했고, 이후에는 어떤 데이터를 DB에 저장하고 무엇을 기준 데이터로 삼을지가 중요했다. 그런데 직접 사용하기 시작하니 다른 것들이 눈에 들어오기 시작했다. 기능은 동작하지만 사용하기에는 불편한 부분들이다. 이번 작업은 새로운 데이터를 추가하거나 DB 구조를 변경하는 대신, 실제로 MyStock을 사용하면서 불편했던 화면과 동작을 정리하는 데 집중했다.Screenshot Mode블로그에 MyStock 관련 글을 쓰면서 가장 먼저 문제가 생겼다. 스크린샷을 찍기가 곤란했다. 대시보드에는 투자원금, 평가금액, 평가손익, 평균매입..
MyStock에 처음 투자성과라는 메뉴를 만들었을 때 내가 보고 싶었던 건 단순했다. 내가 가진 종목들의 수익률을 한 화면에서 보고, KOSPI나 S&P500 같은 시장 지수와 비교하면 내 투자가 괜찮았는지 어느 정도 보일 거라고 생각했다. 그런데 실제로 만들어 놓고 보니 생각보다 별로였다. 종목이 많아질수록 차트는 복잡해졌고, 변동성이 큰 종목 하나가 들어오면 나머지 종목은 상대적으로 눌려 보였다. 무엇보다 현재 보유종목만 기준으로 화면을 만들다 보니 이미 전량 매도한 종목은 아예 사라졌다. 여기서 처음 생각이 바뀌었다. 내가 정말 보고 싶은 게 여러 종목의 수익률을 한 번에 비교하는 화면인가? 곰곰이 생각해보니 아니었다. 더 궁금한 건 내가 언제 샀고, 언제 팔았고, 그 전후로 주가는 어떻게 움직였는..
MyStock의 DB 작업이 거의 끝나가던 시점이었다. DB에 데이터를 쌓는 기반을 만들고 화면에 연결하는 과정에서 생각보다 많은 문제를 겪었다. 특히 Daily 데이터를 언제 최신으로 볼 것인지 제대로 정의하지 않은 채 눈앞의 버그를 하나씩 수정하면서 정책이 계속 복잡해졌다. 문제는 코드만 복잡해진 것이 아니었다. GitHub Codex Connector 리뷰에서 새로운 지적이 나오면 그 상황을 보고 즉흥적으로 조건과 정책을 추가했고, 다시 리뷰를 요청했다. 그러면 새로 추가한 정책이 기존 정책과 충돌하면서 또 다른 지적이 나타났다. 코드를 고치고 리뷰를 다시 돌릴수록 끝에 가까워지는 게 아니라 새로운 문제가 계속 나오는 느낌이었다.Connector 리뷰 정책 변경 필요성처음에는 리뷰에서 지적된 문제를..
DB에 데이터를 저장할 수 있는 기반을 만들었을 때는 큰 산을 넘었다고 생각했다. 기존에는 API에서 데이터를 받아 메모리에 올리고 화면에 보여줬다. 이제 같은 데이터를 DB에도 쌓을 수 있게 됐으니, 화면에서 DB를 먼저 읽도록 연결하면 될 것 같았다. 적어도 처음에는 그게 제일 쉬운 일인 줄 알았다.DB에 데이터가 있으면 먼저 보여주고,부족하거나 오래된 데이터만 API에서 다시 받으면 되지 않을까?문제는 여기서 말한 “부족하다”와 “오래됐다”를 정확히 정의하지 않았다는 것이다. 구현을 시작하고 실제 화면에서 사용해보니 날짜와 시간에 따라 예상하지 못한 상황이 하나씩 나타났다. 그때마다 눈앞의 문제를 해결하는 조건을 추가했다. 각 수정만 놓고 보면 대부분 이유가 있었다. 문제는 전체 요구사항을 먼저 정..
MyStock을 처음 만들 때는 DB를 넣을 생각이 없었다. 한국투자증권에 계좌가 여러 개 있는데, 각 계좌를 하나씩 들어가 보지 않고 보유 종목을 한 화면에서 빠르게 훑어보고 싶었다. 시작은 정말 그 정도였다. 계좌 정보의 원본은 어차피 한국투자증권에 있기 때문에 내가 따로 계좌 정보를 저장하고 관리할 이유가 없다고 생각했다. 프로그램을 실행하면 REST API로 조회하고, 메모리에 올리고, 화면에 보여주면 된다. 종료하면 버리고 다음에 다시 조회하면 된다. 그 당시 요구사항만 놓고 보면 꽤 합리적인 선택이었다.저장하지 않는 설계처음부터 로컬 데이터를 전혀 사용하지 않았던 것은 아니다. 필요한 데이터는 JSON 파일로 간단하게 구성했고, 한때는 Google Drive 동기화 기능도 붙여 사용했다. 그런..
생각보다 빨리 ESP32 최신 SDK 적용에 따른 리팩토링 작업 시기가 앞당겨졌다. 작업을 빠르게 진행하려고 Codex를 적극적으로 쓰기 시작했는데, 개인 계정의 토큰이 녹아가는 게 눈에 보였다. 그래서 회사에서 제공하는 Claude 대신 내가 익숙한 Codex를 쓰는 쪽으로 변경 신청했다. 문제는 회사 계정으로 로그인한 뒤였다. VS Code와 데스크톱 앱까지 회사 계정으로 같이 전환되면서 로그인 상태가 꼬이기 시작했다. 업무는 회사 계정으로 하면 되지만, 회사에서 관리하는 계정과 개인적인 ChatGPT 대화까지 굳이 섞고 싶지는 않았다. 사적인 대화와 개인 작업은 그냥 내 개인 계정으로 쓰고 싶었다.ChatGPT의 제안한 초간단 코드브라우저를 따로 띄우는 수밖에 없나 싶어서 ChatGPT와 방법을 검..