From 4bf3ba9e209310bf0f20ebbef15a14c89c7d5688 Mon Sep 17 00:00:00 2001 From: Guillaume Horel Date: Fri, 23 Mar 2018 13:49:50 -0400 Subject: fix memory leak --- pyisda/credit_index.pyx | 182 ++++++++++++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 82 deletions(-) diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx index 5c5102d..dabed20 100644 --- a/pyisda/credit_index.pyx +++ b/pyisda/credit_index.pyx @@ -3,6 +3,7 @@ from libc.stdlib cimport malloc, free from libc.math cimport nan from libc.string cimport memcpy, memset from libcpp.pair cimport pair +from libcpp.memory cimport unique_ptr from cython.operator cimport dereference as deref from cpython cimport PyObject, Py_INCREF @@ -24,6 +25,9 @@ import warnings cdef inline shared_ptr[TCurve] make_shared(TCurve* ptr) nogil: return shared_ptr[TCurve](ptr, JpmcdsFreeTCurve) +ctypedef TFeeLeg* TFeeLeg_ptr +ctypedef TContingentLeg* TContingentLeg_ptr + cdef TFeeLeg* copyFeeLeg(TFeeLeg* leg) nogil: cdef TFeeLeg* new_leg = malloc(sizeof(TFeeLeg)) cdef size_t size = leg.nbDates * sizeof(TDate) @@ -210,27 +214,12 @@ cdef class CreditIndex(CurveList): sizeof(TContingentLeg)) self.fee_legs = malloc(self._maturities.size() * sizeof(TFeeLeg)) - cdef TStubMethod stub_type - if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0: - raise ValueError("can't convert stub") cdef size_t i + cdef pair[TContingentLeg_ptr, TFeeLeg_ptr] r for i in range(self._maturities.size()): - self.contingent_legs[i] = JpmcdsCdsContingentLegMake(self.start_date, - self._maturities[i], - 1., - True) - - self.fee_legs[i] = JpmcdsCdsFeeLegMake(self.start_date, - self._maturities[i], - True, - NULL, - &stub_type, - 1., - 1.0, - 3, #ACT_360 - 'M', # MODIFIED - b'NONE', - True) + r = get_legs(self._maturities[i], self.start_date) + self.contingent_legs[i] = r.first + self.fee_legs[i] = r.second def __dealloc__(self): if self.contingent_legs is not NULL: @@ -369,11 +358,13 @@ cdef class CreditIndex(CurveList): TDate maturity_c = pydate_to_TDate(maturity) unsigned long mask = 0 vector[double] h - pair[TContingentLeg,TFeeLeg] legs = get_legs(maturity_c, - self.start_date, - self.contingent_legs, - self.fee_legs, - self._maturities) + pair[TContingentLeg_ptr,TFeeLeg_ptr] legs + int i = get_maturity_index(maturity_c, self._maturities) + if i == -1: + legs = get_legs(maturity_c, self.start_date) + else: + legs.first = self.contingent_legs[i] + legs.second = self.fee_legs[i] if epsilon != 0.: mask = fill_mask(maturity_c, self._maturities, self._curves[0]) @@ -384,7 +375,9 @@ cdef class CreditIndex(CurveList): r = pv(self._curves, self.base_date, step_in_date_c, value_date_c, yc._thisptr.get(), legs, recovery_rate, fixed_rate, self._weights, epsilon, h, self.T, mask) - + if i == -1: + free(legs.first) + JpmcdsFeeLegFree(legs.second) return r def theta(self, step_in_date, value_date, maturity, YieldCurve yc not None, @@ -393,32 +386,47 @@ cdef class CreditIndex(CurveList): TDate step_in_date_c = pydate_to_TDate(step_in_date) TDate value_date_c = pydate_to_TDate(value_date) TDate maturity_c = pydate_to_TDate(maturity) + TDate temp vector[double] h - pair[TContingentLeg,TFeeLeg] legs + pair[TContingentLeg_ptr,TFeeLeg_ptr] legs TDateInterval ivl + int i + JpmcdsMakeDateInterval(-1, "Y", &ivl) + JpmcdsDtFwdAny(maturity_c, &ivl, &temp) + if temp < step_in_date_c: + return nan("") if old_pv != old_pv: - legs = get_legs(maturity_c, - self.start_date, - self.contingent_legs, - self.fee_legs, - self._maturities) + i = get_maturity_index(maturity_c, self._maturities) + if i == -1: + legs = get_legs(maturity_c, + self.start_date) + else: + legs.first = self.contingent_legs[i] + legs.second = self.fee_legs[i] old_pv = pv(self._curves, self.base_date, step_in_date_c, value_date_c, yc._thisptr.get(), legs, recovery_rate, fixed_rate, self._weights, 0., h, self.T, 0) - - maturity_c = pydate_to_TDate(maturity) - JpmcdsMakeDateInterval(-1, "Y", &ivl) - JpmcdsDtFwdAny(maturity_c, &ivl, &maturity_c) - legs = get_legs(maturity_c, - self.start_date, - self.contingent_legs, - self.fee_legs, - self._maturities) - return old_pv - pv(self._curves, self.base_date, step_in_date_c, value_date_c, - yc._thisptr.get(), legs, recovery_rate, fixed_rate, - self._weights, 0., h, self.T, 0) + fixed_rate + if i == -1: + free(legs.first) + JpmcdsFeeLegFree(legs.second) + maturity_c = temp + i = get_maturity_index(maturity_c, self._maturities) + if i == -1: + legs = get_legs(maturity_c, + self.start_date) + else: + legs.first = self.contingent_legs[i] + legs.second = self.fee_legs[i] + + cdef r = old_pv - pv(self._curves, self.base_date, step_in_date_c, value_date_c, + yc._thisptr.get(), legs, recovery_rate, fixed_rate, + self._weights, 0., h, self.T, 0) + fixed_rate + if i == -1: + free(legs.first) + JpmcdsFeeLegFree(legs.second) + return r def duration(self, step_in_date, value_date, maturity, YieldCurve yc not None): @@ -427,14 +435,26 @@ cdef class CreditIndex(CurveList): TDate value_date_c = pydate_to_TDate(value_date) TDate maturity_c = pydate_to_TDate(maturity) TFeeLeg* fl + TStubMethod stub_type size_t i - - for i in range(self._maturities.size()): - if self._maturities[i] == maturity_c: - fl = self.fee_legs[i] - break + int found + + found = get_maturity_index(maturity_c, self._maturities) + if found == -1: + JpmcdsStringToStubMethod(b"f/s", &stub_type) + fl = JpmcdsCdsFeeLegMake(self.start_date, + maturity_c, + True, + NULL, + &stub_type, + 1., + 1.0, + 3, #ACT_360 + 'M', # MODIFIED + b'NONE', + True) else: - raise ValueError("maturity is not correct") + fl = self.fee_legs[found] cdef: double fl_pv, r = 0 @@ -452,6 +472,8 @@ cdef class CreditIndex(CurveList): &fl_pv) r += self._weights[i] * fl_pv i += 1 + if found == -1: + JpmcdsFeeLegFree(fl) return r @property @@ -521,38 +543,36 @@ cdef unsigned long fill_mask(const TDate maturity, const vector[TDate]& maturiti mask |= 1 << i return mask -cdef pair[TContingentLeg,TFeeLeg] get_legs(TDate maturity, - TDate start_date, - TContingentLeg** contingent_legs, - TFeeLeg** fee_legs, - vector[TDate]& maturities) nogil: - cdef: - pair[TContingentLeg,TFeeLeg] r - TStubMethod stub_type - +cdef inline int get_maturity_index(TDate maturity, const vector[TDate]& maturities): + cdef size_t i for i in range(maturities.size()): if maturities[i] == maturity: break else: - JpmcdsStringToStubMethod(b"f/s", &stub_type) - r.first = deref(JpmcdsCdsContingentLegMake(start_date, - maturity, - 1., - True)) - r.second = deref(JpmcdsCdsFeeLegMake(start_date, - maturity, - True, - NULL, - &stub_type, - 1., - 1.0, - 3, #ACT_360 - 'M', # MODIFIED - b'NONE', - True)) - return r - r.first = deref(contingent_legs[i]) - r.second = deref(fee_legs[i]) + return -1 + return i + +cdef pair[TContingentLeg_ptr,TFeeLeg_ptr] get_legs(TDate maturity, + TDate start_date) nogil: + cdef: + pair[TContingentLeg_ptr,TFeeLeg_ptr] r + TStubMethod stub_type + JpmcdsStringToStubMethod(b"f/s", &stub_type) + r.first = JpmcdsCdsContingentLegMake(start_date, + maturity, + 1., + True) + r.second = JpmcdsCdsFeeLegMake(start_date, + maturity, + True, + NULL, + &stub_type, + 1., + 1.0, + 3, #ACT_360 + 'M', # MODIFIED + b'NONE', + True) return r cdef double pv(vector[shared_ptr[TCurve]]& curves, @@ -560,7 +580,7 @@ cdef double pv(vector[shared_ptr[TCurve]]& curves, TDate step_in_date, TDate value_date, TCurve* yc, - pair[TContingentLeg,TFeeLeg]& legs, + pair[TContingentLeg_ptr,TFeeLeg_ptr]& legs, double recovery_rate, double fixed_rate, vector[double]& weights, @@ -573,8 +593,6 @@ cdef double pv(vector[shared_ptr[TCurve]]& curves, TCurve* tweaked_curve shared_ptr[TCurve] c size_t i = 0 - TFeeLeg* fl - TContingentLeg* cl if epsilon != 0.: tweaked_curve = JpmcdsCopyCurve(curves[0].get()) @@ -584,7 +602,7 @@ cdef double pv(vector[shared_ptr[TCurve]]& curves, tweak_curve(c.get(), tweaked_curve, epsilon, h, T, mask) else: tweaked_curve = c.get() - JpmcdsContingentLegPV(&legs.first, + JpmcdsContingentLegPV(legs.first, base_date, value_date, step_in_date, @@ -593,7 +611,7 @@ cdef double pv(vector[shared_ptr[TCurve]]& curves, recovery_rate, &cl_pv) - JpmcdsFeeLegPV(&legs.second, + JpmcdsFeeLegPV(legs.second, base_date, step_in_date, value_date, -- cgit v1.2.3-70-g09d2