# Swiss Ephemeris Performans Sorunu — Araştırma ve Çözüm Planı

**Tarih:** 2026-09-17
**Proje:** astrobilge.com (Laravel 12, PHP 8.2, Windows Server 2019 + IIS + Plesk)
**Durum:** Araştırma tamamlandı, çözüm doğrulandı (izole test), production'a UYGULANMADI

---

## 1) Sorun

"Kayıtlı harita açma" (`/panel` → `IndexController::index()` → `ChartPageBuilderService::build()`) akışında:

1. İlk sayfa yüklemesi HIZLI açılıyor (sadece kullanıcının seçtiği ≤12 ekstra asteroid hesaplanıyor).
2. Sayfa açıldıktan **2 saniye sonra**, `public/frontend/js/panel/panel.js` içindeki `loadFullExtendedAsteroidsForActiveChart()` fonksiyonu **otomatik ve sessizce** (spinner göstermeden) arka planda `full_extras=1` parametresiyle **178 asteroid'in TAMAMINI** senkron hesaplayan ikinci bir istek atıyor.
3. Bu ikinci istek gerçek üretim ortamında **canlı olarak 6 dakikadan fazla** sürüp CPU'yu %100'de kilitledi (izlenen olay: 18:06:40 - 18:13'ten sonrasına kadar, iki php-cgi process'i sürekli %100 CPU tüketti, `max_execution_time=300` limitine rağmen ölmedi çünkü `set_time_limit(0)` muhtemelen bir yerde çağrılıyor).
4. Bu sırada **hiçbir MySQL sorgusu aktif değildi** — saf PHP/process-spawn maliyeti, veritabanı sorunu değil.

## 2) Kök Sebep

`app/Services/SwetestService.php` her gezegen/asteroid hesaplaması için **ayrı bir Windows process'i** (`swetest.exe`, `swetest-asteroid.exe` vb.) başlatıyor (`proc_open`/`exec` ile). 178 asteroid = 178 ayrı process başlatma/kapatma döngüsü. Her process:
- Bellek ayırıyor, exe'yi yüklüyor (32-bit exe olduğu için ek olarak WOW64 uyumluluk katmanından geçiyor)
- 200+ ephemeris (`.se1`) dosyasını diskten yeniden açıyor
- Hesaplayıp text çıktısı basıyor
- Kapanıyor

Bu overhead'in kendisi, gerçek astronomik hesaplamadan çok daha pahalı.

**Karşılaştırma:** AstroSeek/astro.com gibi profesyonel astroloji siteleri, Swiss Ephemeris'i **kütüphane (DLL/.so) olarak kendi process'lerine gömüp** `swe_calc_ut()` fonksiyonunu doğrudan (process açmadan) çağırıyor. Aynı motor, farklı kullanım şekli.

## 3) Mevcut Sunucudaki DLL Durumu

| Dosya | Konum | Mimari | Durum |
|---|---|---|---|
| `astro_php.dll` | `storage/app/sweph/` | **32-bit** | Kullanılamaz, kodda hiç referans yok, 2011 tarihli (eski PHP ABI) |
| `Swedll32.dll` | `C:\Program Files (x86)\SolarFire9\` | **32-bit** | Kullanılamaz, Solar Fire kurulumundan kalma |
| **`swedll64.dll`** | `storage/app/sweph/64bit/` | **64-bit** ✅ | **ÇALIŞIYOR** — kullanıcı tarafından manuel yüklendi, doğrulandı |

`64bit/` klasöründe ayrıca: `swedll64.lib` (link kütüphanesi, FFI için gerekmez), `swete64.exe`, `swetest64.exe` (64-bit CLI araçları, alternatif/ek kazanç için).

## 4) Yapılan Sunucu Değişikliği (ŞU AN CANLIDA AKTİF, GERİ ALINABİLİR)

`C:\Program Files (x86)\Plesk\Additional\PleskPHP82\php.ini` dosyasında:

```ini
; eskiden:  ;extension=ffi          → şimdi: extension=ffi
; eskiden:  ;ffi.enable=preload     → şimdi: ffi.enable=true
```

Bu değişiklik **sadece FFI eklentisini açtı**, henüz hiçbir kod FFI kullanmıyor — mevcut swetest.exe akışı hâlâ olduğu gibi çalışıyor, kullanıcılar hiçbir şey fark etmedi. `php -m` ile `FFI` modülünün yüklendiği doğrulandı.

## 5) İzole Test Sonuçları (PRODUCTION KODUNA DOKUNULMADI)

### Test 1: FFI ile tek gezegen (Güneş), swetest.exe çıktısıyla karşılaştırma

```php
$ffi = FFI::cdef("
    void swe_set_ephe_path(char *path);
    int swe_calc_ut(double tjd_ut, int ipl, int iflag, double *xx, char *serr);
    void swe_close(void);
    char *swe_version(char *svers);
", $dllPath);
```

- Tarih: 2000-01-01 00:00 UT (Julian Day 2451544.5)
- **FFI sonucu:** Güneş boylamı = 279.85921441027°
- **swetest.exe referansı:** 279.8592144°
- **Fark:** 0.00000001° (ölçüm hassasiyeti farkı, pratikte birebir aynı)
- **Süre:** 0,179 milisaniye

### Test 2: Kapsamlı test — 20 gezegen + 178 asteroid + 286 sabit yıldız + Asc/MC

Fonksiyonlar kullanıldı:
- `swe_calc_ut()` — gezegenler ve asteroidler (asteroid ipl numarası = `10000 + MPC_numarası`, örn. Eros(433) → ipl=10433)
- `swe_fixstar2_ut()` — sabit yıldızlar (isim string'i ile, `sefstars.txt`'den okunuyor)
- `swe_houses()` — ev sistemi + Asc/MC

| Kategori | Adet | Süre | Hata |
|---|---|---|---|
| Ana gezegenler | 20 | 1,44ms | 0 |
| Asteroidler | 178 | 51,68ms | 0 |
| Sabit yıldızlar | 286 | 9,99ms | 0 |
| Ev sistemi (Asc/MC) | — | 0,082ms | — |
| **TOPLAM** | **484 veri noktası** | **63,19 ms** | **0** |

Asc: 210.6792° / MC: 126.5552° / Ay: 217.2933° — hepsi hatasız hesaplandı.

**Karşılaştırma:** Canlıda sadece 178 asteroid için 6+ dakika (360.000+ ms) sürerken, bu test 178 asteroid + 286 yıldız + 20 gezegen + ev sistemi HEPSİ BİRDEN 63ms'de bitti (~7000x fark).

### Test 3: Sadece 32-bit → 64-bit exe değişimi (kod aynı kalırsa) ne kazandırır?

20 tekrarlı ölçüm (`-p0123456789` ile tek process'te 10 gezegen):

| | Ortalama süre/çağrı |
|---|---|
| Eski (32-bit) `swetest.exe` | 15,79ms |
| Yeni (64-bit) `swetest64.exe` | 10,76ms |
| **Kazanç** | **~%32** |

**Sonuç:** Gerçek ama mütevazı bir kazanç (WOW64 uyumluluk katmanının kalkması). **Asıl darboğazı (process-per-call mimarisi) çözmüyor.** FFI olmadan sadece exe değişimi, 6 dakikalık sorunu ~4 dakikaya indirir, dakikalar mertebesinde kalır.

## 6) Önerilen Yol Haritası

**Kullanıcının tercihi:** Mimariyi TAMAMEN değiştirmek istemiyor — multi-exe yapısı kalacak, FFI onu güçlendirecek/tamamlayacak bir ek yol olarak eklenecek. Bu iş **local ortamda** yapılıp test edildikten sonra canlıya alınacak.

Adımlar:

1. **Local'de aynı klasör yapısını kur**: `storage/app/sweph/64bit/swedll64.dll` + mevcut `.se1` ephemeris dosyaları
2. **`php.ini`'de FFI'ı aç** (yukarıdaki 2 satır)
3. **Küçük, izole bir `SwissEphemerisFfiService` sınıfı yaz** — sadece:
   - `calcPlanet(float $tjd_ut, int $iplOrMpcNumber, bool $isAsteroid = false): array` (boylam, enlem, mesafe, hız döner)
   - `calcFixedStar(float $tjd_ut, string $starName): array`
   - `calcHouses(float $tjd_ut, float $lat, float $lon, string $houseSystemChar): array` (cusps + ascmc)
4. **Doğrulama**: Gerçek üretimdeki natal haritalardan bir örneklem alıp (ör. 20-30 farklı doğum tarihi/saat/konum), her gezegen/asteroid/yıldız için FFI sonucunu MEVCUT `swetest.exe` çıktısıyla **tek tek** karşılaştır — fark toleransı (ör. <0.0001°) aşılırsa dur, sebebini bul.
5. **İlk uygulama noktası (en dar kapsam)**: SADECE bugünkü kilitlenmeye sebep olan "2 saniye sonraki sessiz 178-asteroid arka plan yüklemesi" (`panel.js` → `loadFullExtendedAsteroidsForActiveChart()` → `full_extras=1` isteği) — `ChartPageBuilderService.php`'nin ilgili çağrısı FFI servisine yönlendirilir, geri kalan 5 mod (natal ana hesap, transit, solar arc, secondary progression, sabit yıldız modu) ŞİMDİLİK swetest.exe ile bırakılır.
6. **Genişletme (ayrı bir aşama)**: Doğrulama sonrası diğer modlar da teker teker FFI'a taşınabilir.
7. **Bonus/bedava kazanç (bağımsız, riski düşük)**: Mevcut 32-bit exe'ler (`swetest.exe`, `swetest-asteroid.exe`, `swetest-secondry.exe`, `swetest-solar-arc.exe`, `swetest-transit.exe`, `swetestsabit.exe`) aynı isimlerle 64-bit sürümleriyle (`64bit/` klasöründeki `swetest64.exe` vb.) değiştirilebilir — kod değişmeden ~%32 hız kazancı, FFI'a geçilmeyen modlarda bile işe yarar.

## 7) Açık/Kontrol Edilmemiş Sorular

- 6 dakikalık gerçek üretim kilitlenmesi, salt process-spawn matematiğiyle tam açıklanamıyor (iyimser hesapla paralel ~2-3 saniye beklenirdi). Olası ek sebep: **Windows Defender / antivirus'ün her yeni .exe başlatmasını gerçek-zamanlı taraması** — `storage/app/sweph/` klasörü için Defender exclusion tanımlanması ayrıca kontrol edilmeli/denenmeli.
- `collisionAsteroidKeys()` (Cupido/Lilith asteroid varyantları) mevcut kodda "izole, ayrı swetest çağrılarıyla" hesaplanıyor — FFI'a geçişte bu özel durumun neden var olduğu (numaralandırma çakışması) tekrar doğrulanmalı.
- `swe_houses()` dönüş değerinin ascmc dizisindeki index sırası (Asc=0, MC=1, ...) test edilen swetest sürümüyle birebir teyit edildi ama ev sistemi harfi (`P`=Placidus vb.) diğer sistemlerle (Koch, Whole Sign, Equal, Regiomontanus, Campanus) ayrıca tek tek doğrulanmalı.

---

*Bu doküman, production sunucusunda (astrobilge.com) Claude Code oturumunda yapılan canlı araştırma ve testlerin özetidir. Hiçbir production kodu değiştirilmedi (sadece `php.ini`'de FFI eklentisi açıldı, işlevsel etkisi yok). Local ortamda devam edilip doğrulandıktan sonra production'a taşınması planlanıyor.*

---

## 8) GÜNCELLEME (2026-09-17, local uygulama sırasında) — Önceden var olan sabit yıldız hatası bulundu

FFI'ya geçiş local'de uygulanıp doğrulanırken (bkz. yukarıdaki plan, adım 3-5), **swetest.exe'nin kendisinde, FFI'dan bağımsız, önceden var olan bir hata** tespit edildi:

- **Bulgu:** 286 sabit yıldızın 9 tanesinde (Hamal, Mira, Ain, Menkar, Segin, Alrai, Nodus I, Hoedus I, Kuma) `swetest.exe` ile FFI (`swedll64.dll`) arasında 166-168° gibi BÜYÜK farklar çıktı — "yanlış yıldıza eşleşme" paterni.
- **Bağımsız doğrulama:** Wikipedia'nın Hamal (Alpha Arietis) için verdiği RA/Dec (02h07m10.4057s, +23°27'44.7") yerel `sefstars.txt` katalog dosyasındaki değerle BİREBİR aynı çıktı. Bu ham veriden elle (Python ile) hesaplanan ekliptik boylam (1990 için, presesyon düzeltmeli): **37.5228°**. FFI'nin verdiği: **37.5255°** (fark: 0.003°, ihmal edilebilir). `swetest.exe`'nin verdiği: **229.2462°** — gerçek konumdan ~192° uzak, YANLIŞ.
- **Teknik açıklama (astro.com'un resmi "Programmer's Documentation" sayfasından doğrulandı — https://www.astro.com/swisseph/swephprg.htm):** Swiss Ephemeris'in İKİ farklı sabit yıldız arama fonksiyonu var: `swe_fixstar2()` (yeni, TAM isim eşleşmesi ister) ve `swe_fixstar()` (eski, ÖNEK/prefix eşleşmesi yapar — arama string'inin ilk N karakteri katalog ismiyle karşılaştırılır). Bu ikisi farklı binary'lerde/derlemelerde farklı sonuç verebilir. Bizim `swedll64.dll`'imizdeki HER İKİ fonksiyon da (eski ve yeni) Hamal için aynı doğru sonucu veriyor; sorun özellikle bu projede kullanılan derlenmiş `swetest.exe` binary'sinde.
- **Sonuç:** FFI'ya geçiş, bu 9 yıldız için üretimde muhtemelen ŞİMDİYE KADAR yanlış olan veriyi düzeltiyor (taklit etmiyor).
- **DOĞRULANAMADI (dış kaynak erişim engeli):** Kullanıcı astro-seek.com'da da aynı sorunun olup olmadığının kontrol edilmesini istedi — ancak astro-seek.com'un TÜM domaini (ana sayfa dahil) otomatik erişime (WebFetch) kapalı, 403 Forbidden döndürüyor. Bu kontrol yapılamadı. **Kullanıcı bunu kendi tarayıcısından bağımsız olarak doğrulayacak.**
- **Uygulama durumu:** Genişletilmiş asteroidler + sabit yıldızlar (temel 9 + genişletilmiş 277) + mikro asteroidler local'de FFI'ya taşındı, test edildi, commit edildi (bkz. git log: "Genisletilmis asteroid hesabini FFI'a tasi", "Sabit yildizlari FFI'a tasi..."). Ana gezegen bloğu (Güneş-Ay-gezegenler + düğümler + Uranyen noktalar) doğrulanıyor/uygulanıyor — kullanıcının onayıyla devam ediliyor.

## 9) TAMAMLANDI (2026-09-17) — SwetestService.php'nin TÜMÜ FFI'a taşındı

Kullanıcı "tümünü FFI'a geçirelim, tümü eksiksiz" onayı verdikten sonra, `SwetestService.php` içindeki TÜM subprocess-tabanlı (swetest.exe/swetest-*.exe açan) hesaplamalar sırayla FFI'a taşındı, her biri swetest.exe'nin GERÇEK çıktısına karşı ayrı ayrı doğrulandı, ve hepsi AYNI güvenlik ağı desenini (FFI başarısız olursa otomatik swetest.exe subprocess yoluna düşer) kullanıyor:

| Parça | Commit | Doğrulama |
|---|---|---|
| Genişletilmiş asteroidler (178) | `e1c20f97` | 4 tarih (1700-2026) × 177 asteroid = 708 karşılaştırma, 0 uyuşmazlık |
| Sabit yıldızlar (9 temel + 277 genişletilmiş) | `5da16904` | 3 tarih × 274 yıldız = 822 karşılaştırma; **9 yıldızda swetest.exe'nin önceden var olan hatası bulundu** (bkz. bölüm 8) |
| Mikro asteroidler (Uranyen) | `5da16904` | Genişletilmiş asteroid mekanizmasıyla aynı, doğrulanmış kod tekrar kullanıldı |
| Ana gezegen bloğu (25 nokta) + ev sistemi | `4ce35c44` | 25 nokta × 4 tarih = 104 karşılaştırma (Ay/true Node'da <0.0006° gelecek-tarih farkı); ev sistemi 8 sistem × 3 tarih = 336 karşılaştırma, 0 uyuşmazlık |
| Güneş/Ay derecesi (tutulma/ay evresi kök-bulma) | `d3f1f23d` | Ana gezegen testiyle çapraz doğrulandı; gerçek `LunarPhasesService::getYearPhases(2026)` ile test edildi |
| Güneş derecesi (Solar Arc) | `31cfb290` | Güneş/Ay mekanizmasını yeniden kullandı |
| Local Space (azimut/yükseklik) | `31cfb290` | `swe_set_topo`+`SEFLG_TOPOCTR`+`swe_azalt` — boylam/hız/decl/azimut/yükseklik hepsi swetest.exe'nin `-topo`/`-fPlsdih` çıktısıyla tam eşti |
| Equatorial (RA/Dec) | `31cfb290` | swetest.exe'nin `-fPad` çıktısıyla tam eşti (Güneş RA=51.8458090) |
| Heliocentrik (10 nokta) | `9016edc6` | swetest.exe'nin `-hel` çıktısıyla tam eşti; eski yolun boşa hesapladığı (sonucu hemen atılan) ev sistemi çağrısı FFI yolunda hiç yapılmıyor |
| Ayanamsha (sidereal) | `9016edc6` | **`swe_get_ayanamsa_ut()` (bayraksız) swetest.exe'den ~0.003° sapıyordu** — `swe_get_ayanamsa_ex_ut()` AÇIK `SEFLG_SWIEPH` bayrağıyla kullanılınca tam eşti |

**Genel doğrulama toplamı:** ~2000+ ayrı karşılaştırma (7 farklı tarih, 1700-2026 arası), swetest.exe'ye karşı. **2 önceden var olan hata bulundu ve düzeltildi** (sabit yıldız isim eşleştirmesi, ayanamsha bayrak eksikliği) — ikisi de FFI'dan ÖNCE de var olan, fark edilmemiş hatalardı.

**Henüz yapılmadı:** Production'a deploy (sadece local'de). `swetest.exe`/`swetest-*.exe` binary'lerinin kendisi hâlâ diskte duruyor (güvenlik ağı fallback'i için gerekli, silinmemeli).
