lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Would manual optimization help here?


From: Greg Chicares
Subject: [lmi] Would manual optimization help here?
Date: Fri, 26 Mar 2021 14:59:46 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.0

Vadim--In this century, should we never even contemplate manual
optimizations? In particular, here, in a loop that iterates once
for every month in the year, with some values that depend on the
year but not the month:

AccountValue::TxSetCoiCharge() ...
    NAAR = round_naar().c
        ( DBReflectingCorr * DBDiscountRate[Year]
        - dblize(std::max(C0, TotalAccountValue()))
        );

I'm wondering whether I should hoist DBDiscountRate[Year], to
perform the subscripting once instead of twelve times. Elsewhere,
lmi actually does that--e.g.,

'account_value.hpp': [cached scalar value]
    double       YearsDcvIntRate;

'ihs_acctval.cpp': [performed only once each year]
    YearsDcvIntRate         = i7702_->ic_usual()[Year];

'ihs_avmly.cpp': [performed each month, in each year]
        Dcv += round_interest_credit().c(YearsDcvIntRate * Dcv);

and my question is whether I should do something similar, adding
a new 'double YearsDBDiscountRate', setting it once per year
(say, 100 times for 100 years), and then using it 1200 times.

Alternatively, if that's not likely to help, should I rewrite
old code to remove those cached scalars, e.g.:
-    Dcv += round_interest_credit().c(YearsDcvIntRate * Dcv);
-    Dcv += round_interest_credit().c(i7702_->ic_usual()[Year] * Dcv);
in the example above?

Feeling enervated after that second covid vaccination yesterday,
I hesitate to do anything ambitious today, but I figured this is
a small enough question that I ought to be able to figure out the
answer. Not. I hadn't used gdb in about a decade, but I remember
enough to muddle through it, mechanically...but I don't know what
the disassembly means. Should gdb help me answer my question above?

Here's a gdb session; annotations have '#' in the left margin.

# Start gdb. Symbols loaded from the pc-linux-gnu '.so' aren't
# loaded immediately, so 'start' the program.

/opt/lmi/bin[0]$gdb -q lmi_wx_shared
Reading symbols from lmi_wx_shared...
(gdb) info func TxSetCoi
All functions matching regular expression "TxSetCoi":
(gdb) start
# ...
(gdb) info func TxSetCoi
All functions matching regular expression "TxSetCoi":

File /opt/lmi/src/lmi/ihs_avmly.cpp:
1762:   void AccountValue::TxSetCoiCharge();

Non-debugging symbols:
0x00007ffff7a118f0  AccountValue::TxSetCoiCharge()@plt

# I didn't have any luck trying to 'disas' yet, so I set a
# breakpoint and used 'run':

(gdb) break /opt/lmi/src/lmi/ihs_avmly.cpp:1762
Breakpoint 2 at 0x7ffff7c58160: file /opt/lmi/src/lmi/ihs_avmly.cpp, line 1791.
(gdb) run  --ash_nazg --data_path=/opt/lmi/data
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/lmi/bin/lmi_wx_shared --ash_nazg 
--data_path=/opt/lmi/data
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

# Go to lmi's GUI; File | New | Illustration | OK

Thread 1 "lmi_wx_shared" hit Breakpoint 2, AccountValue::TxSetCoiCharge 
(this=this@entry=
    0x7fffffffae80) at /opt/lmi/src/lmi/ihs_avmly.cpp:1791
1791        double coi_rate = GetBandedCoiRates(GenBasis_, ActualSpecAmt)[Year];

(gdb) disas /s

# ...omit what looks like a prologue

1774        NAAR = round_naar().c
--Type <RET> for more, q to quit, c to continue without paging--

# [hit 'c']

1775            ( DBReflectingCorr * DBDiscountRate[Year]
   0x00007ffff7c58010 <+16>:    movslq 0x18c0(%rdi),%rdx
   0x00007ffff7c58017 <+23>:    mov    0x948(%rdi),%rax

# ...disassembly of classes currency and round_to, and
# of some libstdc++ stuff...

/opt/lmi/src/lmi/ihs_avmly.cpp:
1777            );
   0x00007ffff7c5806f <+111>:   movsd  %xmm1,-0x18(%rbp)

# That doesn't seem to tell me much. It looks like all the real
# work is done in instructions listed under called functions.
# The disassembly listed under calls into the currency and rounding
# functions seems unremarkable, but then I see this, which suggests
# to my unpracticed eye that a lot of real work is being done here,
# and annotating it as "stl_vector.h" doesn't mean that this is
# actually all part of std::vector::operator[]:

/usr/include/c++/10/bits/stl_vector.h:
1061          operator[](size_type __n) const _GLIBCXX_NOEXCEPT
   0x00007ffff7c58176 <+374>:   movslq 0x18c0(%rbx),%rdx
   0x00007ffff7c5817d <+381>:   movsd  0x1900(%rbx),%xmm0
   0x00007ffff7c58185 <+389>:   divsd  0xb6083(%rip),%xmm0        # 
0x7ffff7d0e210
   0x00007ffff7c5818d <+397>:   mov    (%rax),%rax
   0x00007ffff7c58190 <+400>:   fldt   0xc30(%rbx)

# Already, something curious is going on. This is a vector of
# double, for which x86_64 pc-linux-gnu wouldn't use FLDT, AIUI,
# because that's an x87 load-tenbyte instruction. No 'long double'
# variable is used except in lmi's round_to class, so that class's
# code has to be what's shown here, AFAICT. It continues (probably
# there's nothing interesting here, but I don't dare snip too much):

   0x00007ffff7c58196 <+406>:   movsd  (%rax,%rdx,8),%xmm1
   0x00007ffff7c5819b <+411>:   mulsd  %xmm1,%xmm0
   0x00007ffff7c5819f <+415>:   movsd  %xmm1,0x1bb0(%rbx)
   0x00007ffff7c581a7 <+423>:   movsd  %xmm0,-0x18(%rbp)
   0x00007ffff7c581ac <+428>:   fmull  -0x18(%rbp)
   0x00007ffff7c581af <+431>:   fstpl  -0x18(%rbp)
   0x00007ffff7c581b2 <+434>:   movsd  -0x18(%rbp),%xmm0
   0x00007ffff7c581b7 <+439>:   call   *0xc80(%rbx)
   0x00007ffff7c581bd <+445>:   fldt   0xc70(%rbx)
   0x00007ffff7c581c3 <+451>:   movsd  %xmm0,-0x18(%rbp)
   0x00007ffff7c581c8 <+456>:   fmull  -0x18(%rbp)
   0x00007ffff7c581cb <+459>:   fstpl  -0x18(%rbp)
   0x00007ffff7c581ce <+462>:   movsd  -0x18(%rbp),%xmm0
   0x00007ffff7c581d3 <+467>:   fldt   0xc30(%rbx)
   0x00007ffff7c581d9 <+473>:   movsd  %xmm0,0x1908(%rbx)
   0x00007ffff7c581e1 <+481>:   addsd  0x1c58(%rbx),%xmm0
   0x00007ffff7c581e9 <+489>:   movsd  %xmm0,0x1c58(%rbx)
   0x00007ffff7c581f1 <+497>:   movsd  0x1960(%rbx),%xmm0
   0x00007ffff7c581f9 <+505>:   divsd  0xb600f(%rip),%xmm0        # 
0x7ffff7d0e210
   0x00007ffff7c58201 <+513>:   mulsd  0x1ad8(%rbx),%xmm0
   0x00007ffff7c58209 <+521>:   movsd  %xmm0,-0x18(%rbp)
   0x00007ffff7c5820e <+526>:   fmull  -0x18(%rbp)
   0x00007ffff7c58211 <+529>:   fstpl  -0x18(%rbp)
   0x00007ffff7c58214 <+532>:   movsd  -0x18(%rbp),%xmm0
   0x00007ffff7c58219 <+537>:   call   *0xc80(%rbx)
   0x00007ffff7c5821f <+543>:   fldt   0xc70(%rbx)
   0x00007ffff7c58225 <+549>:   movsd  %xmm0,-0x18(%rbp)
   0x00007ffff7c5822a <+554>:   fmull  -0x18(%rbp)
   0x00007ffff7c5822d <+557>:   fstpl  0x1968(%rbx)
   0x00007ffff7c58233 <+563>:   mov    -0x8(%rbp),%rbx
   0x00007ffff7c58237 <+567>:   leave  
   0x00007ffff7c58238 <+568>:   ret    
   0x00007ffff7c58239 <+569>:   nopl   0x0(%rax)
   0x00007ffff7c58240 <+576>:   divsd  0xb5fc8(%rip),%xmm0        # 
0x7ffff7d0e210

So...would it be worth hoisting the vector indexing from the
monthly to the yearly level? I can't tell. I asked konsole
to search the screen buffer for the address of the vector
that's indexed:

(gdb) p &DBDiscountRate
$2 = (std::vector<double, std::allocator<double> > *) 0x7fffffffb7c8

but it found no other occurrence of "b7c8". But if the
compiler hoisted that, then why would gdb say that it's
disassembling operator[]?

Is there a better gdb technique, or a better tool, to help
me find the answer to my question? Is gdb telling me, in an
inscrutable way, that the question is silly and gcc will
already optimize better than I could do manually?


reply via email to

[Prev in Thread] Current Thread [Next in Thread]