8 Ağustos 2016 Pazartesi

boost python

Giriş
Şu satırları dahil ederiz.
#include <boost/python.hpp>
#include <Python.h>
Rahat kullanmak için şu satırı dahil ederiz.
using namespace boost::python;
class_ Sınıfı
python'dan C++ Kullanmak yazısına taşıdım.

stl_iterator Sınıfı
Şu satırı dahil ederiz.
#include <boost/python/stl_iterator.hpp>
python tarafından döndürülen bir liste olsun. Şöyle dolaşırız.
list records = call_method<list>(...);
stl_input_iterator<tuple> end;
for (stl_input_iterator<tuple> itr(records); itr != end;++itr)
{
  auto record = *itr;
  std::string tick = call_method<std::string>(record.ptr(), "__getitem__", 0);
  ...
}
Free Style metodlar
exec metodu
Şöyle yaparız.
namespace py = boost::python;

int main()
{
  // Must be called before any boost::python functions
  Py_Initialize();
  // import the main module
  py::object main_module = py::import("__main__");
  // load the dictionary object out of the main module
  py::object main_namespace = main_module.attr("__dict__");
  // run simple code within the main namespace using the boost::python::exec 
  //  function
  py::exec("print ('Hello, world')", main_namespace);
  // any valid Python will execute
  py::exec("print ('Hello, world')[3:5]", main_namespace);
}


2 Ağustos 2016 Salı

GDB

gdb
gdb seçenekleri yazısına taşıdım.

ptrace
debugger kullanmadan ptrace ile sistem çağrıları da görülebilir. Kendimize ait olmayan uygulamarı ptrace yapabilmek için burada açıklandığı gibi CAP_SYS_PTRACE hakkı lazım. Uygulama prctl() ile trace edilmemeyi isteyebilir.

WinDbg
Hiç kullanmadım. Dosya uzanstısı mdmp şeklinde.


valgrind
valgrind yazısına taşıdım.

Visual Studio
valgrind yazısına taşıdım.

Java Debugger
Yeri gelmişken, Java debugger ile gdb'yi de karşılaştırmak gerekir. Java debugger ile değişkenlere bakarken
object={java.lang.Object@77}
şeklinde bir gösterim görüyoruz. Bu gösterimde nesnenin tipi, ve hashcode değeri belirtiliyor.

callgrind
callgrind kodu instrumente eder. Bu yüzden yavaştır. Very Sleepy gibi araçlar ise istatistiki yöntemlerle çalıştıkları için daha hızlıdırlar.

gcov
kod gcc'nin şu seçenekleri ile derlenir
-fprofile-arcs -ftest-coverage
Şu seçeneği ile linklenir.
-lgcov
Derlerken ve linklerken sadece -coverage kullanmamız da sanırım yeterli oluyor. Sunumda da böyle yazıyor.
-coverage
Daha sonra gcov uygulaması derleyicinin çalıştırıldığı dizinde çalıştırılır. Şöyle bir kod yapımız olsun.
-root
   -source
      -dir1
         -file.cpp
      -dir2
         -file.cpp
derleyici root dizininden çalıştırılıyorsa, gcov da root dizininden çalıştırılır. Çıktı olarak gcno ve gcda uzantılı bir sürü ara dosya üretilir.
-root
   -source
      -dir1
         -file.cpp
         -file.o
         -file.gcno
         -file.gcda
      -dir2
         -file.cpp
         -file.o
         -file.gcno
         -file.gcda
-s seçeneği
source dizini belirtir
gcov -p -s source source/dir1/file.cpp

lcov
lcov komutu yazısına taşıdım.

gprof
gprof'un çıktısı şu şekildedir. Okuması biraz zordur.
%   cumulative   self              self     total           
 time   seconds  seconds    calls   s/call   s/call  name    
71.93    907.85   907.85   201280     0.00     0.00  ForceCalcs
 2.61   1237.18    33.00     1258     0.03     1.00  Heap
 1.53   1256.45    19.28     1258     0.02     0.02  AdjustSP
 0.01   1261.61     0.07     1258     0.00     0.00  Boundary
 0.00   1261.61     0.00      100     0.00     0.00  Profile
 0.00   1261.61     0.00        2     0.00     0.00  MakeMap
 0.00   1261.61     0.00        1     0.00     0.18  Initialize
Çıktıyı görsel olarak görmek için şöyle yapabiliriz.
gprof executable | gprof2dot.py | dot -T pdf > profile.pdf

google-pprof
Şöyle yaparız. bench-profiled benim uygulamamın ismi
$ google-pprof bench-profiled timing.pprof
Using local file bench-profiled.
Using local file timing.pprof.
Welcome to pprof!  For help, type 'help'.
(pprof) top 10
Total: 593 samples
     154  26.0%  26.0%      377  63.6% sqlite3_randomness
     134  22.6%  48.6%      557  93.9% sqlite3_reset
      83  14.0%  62.6%       83  14.0% __read_nocancel
      61  10.3%  72.8%       61  10.3% sqlite3_strnicmp
      41   6.9%  79.8%       46   7.8% sqlite3_free_table
      26   4.4%  84.1%       26   4.4% sqlite3_uri_parameter
      25   4.2%  88.4%       25   4.2% llseek
      13   2.2%  90.6%      121  20.4% sqlite3_db_config
      12   2.0%  92.6%       12   2.0% __pthread_mutex_unlock_usercnt (inline)
      10   1.7%  94.3%       10   1.7% __GI___pthread_mutex_lock


1 Ağustos 2016 Pazartesi

boost log

Giriş
static linklemek için şöyle yaparız.
gcc ... ..../boost_1_61_0_b1/stage/lib/libboost_log.a ...
Dinamik linklemek için şöyle yaparız.
gcc ... -lboost_log ...
Dinamik linklemek için şu macroyu kullanırız.
BOOST_ALL_DYN_LINK

Konuya girmeden önce boost log'lama kütüphanesinin tasarımına bakmak gerekir. Kodlarken şu satırlar faydalı olabilir.
namespace logging = boost::log;
namespace src = boost::log::sources;
namespace sinks = boost::log::sinks;
Free Style Metodlar
add_common_attributes metodu
Tam ne işe yarar anlamadım. Şöyle yaparız.
#include <boost/log/utility/setup/common_attributes.hpp>
namespace logging = boost::log;
logging::add_common_attributes();
add_console_log metodu
add_console_log metodu yazısına taşıdım.

add_file_log metodu
add_file_log metodu yazısına taşıdım.

Trivial Logger
Şu satırı dahil ederiz.
#include <boost/log/trivial.hpp>
Trivial Logger kullanması en kolay yöntem. trivial.hpp içinde global bir severity_logger_mt logger - yani source - tanımlar ve tüm kod onu kullanır. Verilen log mesajı hemen consolda görülebilir. Örnek:
int main(int, char*[])
{

  BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
  BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
  BOOST_LOG_TRIVIAL(info) << "An informational severity message";
  BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
  BOOST_LOG_TRIVIAL(error) << "An error severity message";
  BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
}
logger Sınıfı
Örnekte lg benim logger nesnem. Gerekli ayar ve değerleri atadıktan sonra şu macro ile kullanılıyor.
src::logger lg;
BOOST_LOG(lg) << "Hello world!";
N tane logger nesnesi yaratabilirim. logging::core nesnesi sadece bir tane.

Logger Çıktısı
İster Trivial Logger ister benim yarattığım logger kullanılsın, ilk çıktının şekli şöyledir. timestamp + current thread id + severity level + log mesajı.

[2016-03-22 13:43:53.481522] [0x80000f4] [info] Hello

Çıktı değiştirmek için şöyle yaparım.

severity_logger_mt Sınıfı
severity seviyesine göre filtreme sağlar. kendi .h dosyama şu tanımı yaparım
typedef src::severity_logger_mt <severity_level> logger_t;
std::wstring kullanabilmek için şöyle yaparız.
typedef src::wseverity_logger_mt <severity_level> logger_t;
Kendi logger .cpp dosyama iskelet olarak şunu yazarım.
BOOST_LOG_GLOBAL_LOGGER_INIT(logger, src::severity_logger_mt)
{
  logger_t lg;
  logging::add_common_attributes();
  ...
}
Tam örnek burada.

severity_channel_logger Sınıfı
Hem severity hem de channel özelliğine sahip bir logger yaratır.
typedef src::severity_channel_logger< severity_level, std::string > logger_type;

logger_type lg_a(keywords::channel = "A");
logger_type lg_b(keywords::channel = "B");

BOOST_LOG_SEV(lg_a, info) << "Hello, A.log!";
BOOST_LOG_SEV(lg_b, info) << "Hello, B.log!";
Eğer sinkeri de channel'ları kullanacak şekilde yaratırsam her sink sadece ilişkili olduğu channel'dan gelen logları alır. Şöyle yaparız.
BOOST_LOG_ATTRIBUTE_KEYWORD(a_severity, "Severity", severity_level)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_channel, "Channel", std::string)

logging::add_file_log(
    keywords::file_name = "A.log",
    keywords::filter = a_channel == "A");

logging::add_file_log(
    keywords::file_name = "B.log",
    keywords::filter = a_channel == "B");
record_view Sınıfı
Elimizde şu iki sınıf olsun

logging::record_view& record = ...;
logging::formatting_ostream stream = ...;
Şöyle yaparız.

stream << record[a_timestamp] << " "
       << record[a_thread_id]
       << " [" << severity << "] "
       << record[logging::expressions::smessage]
       << "\e[0m";
core Sınıfı
remove metodu
Şöyle yaparız.
typedef sinks::synchronous_sink <sinks::text_file_backend> SPFileSink;
SPFileSink logFileSink = ...;
boost::log::core::get()->remove_sink (logFileSink);

Sinkler
Her sink her logger'dan mesaj alabilir.
Şu sinkler var.

synchronous_sink
Bu sınıfı tanımlamak için şöyle yaparız.
typedef sinks::synchronous_sink <sinks::text_file_backend> T;

Sink BackEnd Sınıfları
Şu sink back endleri var.

text_ostream_backend sınıfı
Şöyle kurulur.
// Construct the sink
typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();
ofstream şöyle eklenir.
// Add a stream to write log to
sink->locked_backend()->add_stream(
        boost::make_shared< std::ofstream >("sample.log"));
flush modu şöyle ayarlanır.
sink->locked_backend()->auto_flush(true);
sink logging::core nesnesine şöyle eklenir.
// Register the sink in the logging core
logging::core::get()->add_sink(sink);
text_file_backend sınıfı
text_file_backend Sınıfı yazısına taşıdım.

Kendi Sınıfım İçin Stream Operator
Şöyle yaparım.
boost::log::formatting_ostream& operator<<(boost::log::formatting_ostream& p,
                                          const MyClass& c)
{
  ...
  return p;
}
BOOST_LOG_ATTRIBUTE_KEYWORD 
Şöyle yaparız
BOOST_LOG_ATTRIBUTE_KEYWORD(a_timestamp, "TimeStamp",
 attrs::local_clock::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(a_thread_id, "ThreadID",
 attrs::current_thread_id::value_type)