TrickDiary このページをアンテナに追加 RSSフィード

2010-02-16

[][] C#バグベアード擬き エンジン部

昨日の続きでエンジン部をC#へ移植。まだ詰めが残ってるけど、これでほぼできあがり。

using System;
using System.Collections.Generic;
#if BUG_WITHOUT_LOCATION_INFO
#else
using System.Diagnostics;
#endif

public class bug_puppy
{

    // 省略


    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_message
    //

    public class bug_message
    {
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string file;
        public int line;
#if BUG_FUNCTION_NAME
        public string function_name;
#endif
#endif
        public string message;

        public bug_message()
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = null;
            line = 0;
#if BUG_FUNCTION_NAME
            function_name = null;
#endif
#endif
        }
        public bug_message(string a_message)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = null;
            line = 0;
#if BUG_FUNCTION_NAME
            function_name = null;
#endif
#endif
            message = a_message;
        }
#if BUG_WITHOUT_LOCATION_INFO
#else
#if BUG_FUNCTION_NAME
        public bug_message(string a_file, int a_line, string a_function_name)
#else
        public bug_message(string a_file, int a_line)
#endif
        {
            file = a_file;
            line = a_line;
#if BUG_FUNCTION_NAME
            function_name = a_function_name;
#endif
            message = null;
        }
#if BUG_FUNCTION_NAME
        public bug_message(string a_file, int a_line, string a_function_name, string a_message)
#else
        public bug_message(string a_file, int a_line, string a_message)
#endif
        {
            file = a_file;
            line = a_line;
#if BUG_FUNCTION_NAME
            function_name = a_function_name;
#endif
            message = a_message;
        }
#endif
        public bug_message(bug_message a)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a.message;
        }
        public bug_message(bug_message a, string a_message)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a_message;
        }
            
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string get_file()
        {
            if (string.IsNullOrEmpty(file))
            {
                return "<?unknown?>#?";
            }
            else
            {
                return file;
            }
        }
        public int get_line()
        {
            return line;
        }
#if BUG_FUNCTION_NAME
        string get_function_name()
        {
            if (string.IsNullOrEmpty(function_name))
            {
                return "unknown_function";
            }
            else
            {
                return function_name;
            }
        }
#endif
#endif
        public string get_message()
        {
            return message;
        }
#if BUG_WITHOUT_LOCATION_INFO
#else
        public string get_location()
        {
            if (string.IsNullOrEmpty(file))
            {
                return "<?unknown?>#?";
            }
            else
            {
#if BUG_FUNCTION_NAME
                return string.Format("<{0}>#{1}@{2}", file, line.ToString(), get_function_name().c_str());
#else
                return string.Format("<{0}>#{1}", file, line.ToString());
#endif
            }
        }
#endif

        public string get_message_ex()
        {
#if BUG_WITHOUT_LOCATION_INFO
            return message;
#else
            if (string.IsNullOrEmpty(message))
            {
                return get_location();
            }
            else
            {
                return message;
            }
#endif
        }

        public string get_full_message()
        {
#if BUG_WITHOUT_LOCATION_INFO
            return message;
#else
            if (string.IsNullOrEmpty(file))
            {
                return message;
            }
            else
            if (string.IsNullOrEmpty(message))
            {
                return get_location();
            }
            else
            {
                return string.Format("{0} {1}", message, get_location());
            }
#endif
        }

        public bug_message create(string a_message)
        {
            return new bug_message(this, a_message);
        }

        public bug_message assign(bug_message a)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            file = a.file;
            line = a.line;
#if BUG_FUNCTION_NAME
            function_name = a.function_name;
#endif
#endif
            message = a.message;
            return this;
        }
        
        public bool Equals (bug_message a)
        {
            return
#if BUG_WITHOUT_LOCATION_INFO
#else
                file == a.file &&
                line == a.line &&
#if BUG_FUNCTION_NAME
                function_name == a.function_name &&
#endif
#endif
                message == a.message;
        }
        public bool less_than(bug_message a)
        {
            return
#if BUG_WITHOUT_LOCATION_INFO
#else
                file.CompareTo(a.file) < 0 ||
                (
                    file == a.file &&
                    (
                        line < a.line ||
                        (
                            line == a.line &&
                            (
#if BUG_FUNCTION_NAME
                                function_name.CompareTo(a.function_name) < 0 ||
                                (
                                    function_name == a.function_name &&
                                    (
#endif
#endif
                                        message.CompareTo(a.message) < 0
#if BUG_WITHOUT_LOCATION_INFO
#else
#if BUG_FUNCTION_NAME
                                    )
                                )
#endif
                            )
                        )
                    )
                )
#endif
                ;
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profiler
    //
    
    public delegate void bug_writer(bug_message text, IEnumerable<string> tags);

    [ThreadStatic] public static bug_writer trace_writer = null;
    [ThreadStatic] public static string last_stamp = null;

    class bug_profiler :IDisposable
    {
        bug_writer profile_writer;
        public int level;
        int bug_scope_count;
        long bug_scope_begin_time;
        Stack<bug_profile_time_score> score_stack = new Stack<bug_profile_time_score>();
        Dictionary<bug_message, bug_profile_time_score_set> profile_db = new Dictionary<bug_message, bug_profile_time_score_set>();
        
        long overall_start_time;
        bug_profile_time_score overall_time_score = new bug_profile_time_score();

        public bug_profiler(bug_writer a_profile_writer)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            begin_bug_time(a_current_tick);

            profile_writer = a_profile_writer;
            level = 0;
            bug_scope_count = 0;
            bug_scope_begin_time = 0;
            overall_start_time = a_current_tick;
            push_time_score(overall_time_score);

            end_bug_time();
        }
        public void Dispose()
        {
        }

        [ThreadStatic] public static bug_profiler instance = null;

        //public static bug_profiler get_instance()
        //{
        //    return instance;
        //}

        public void push_time_score(bug_profile_time_score a_time_score, long a_current_tick)
        {
            if (null != this)
            {
                if (0 < bug_scope_count)
                {
                    if (0 < score_stack.Count)
                    {
                        if (bug_scope_begin_time < a_current_tick)
                        {
                            score_stack.Peek().self_time_set.bug_time += a_current_tick -bug_scope_begin_time;
                            bug_scope_begin_time = a_current_tick;
                        }
                    }
                }
                score_stack.Push(a_time_score);
            }
        }
        public void push_time_score(bug_profile_time_score a_time_score)
        {
            push_time_score(a_time_score, bug_profile_time_type.get_current_tick());
        }
        public void add_time_score(bug_message a_message, string a_start_stamp, bug_profile_time_score a_time_score)
        {
            if (null != this)
            {
                if (0 < score_stack.Count)
                {
                    score_stack.Peek().sub_time_set.add(a_time_score.get_all_time_set());
                }
                profile_db[a_message].add_score(a_start_stamp, a_time_score);
            }
        }
        public void pop_time_score(long a_current_tick)
        {
            if (null != this)
            {
                if (0 < score_stack.Count)
                {
                    if (0 < bug_scope_count)
                    {
                        if (bug_scope_begin_time < a_current_tick)
                        {
                            score_stack.Peek().self_time_set.bug_time += a_current_tick - bug_scope_begin_time;
                            bug_scope_begin_time = a_current_tick;
                        }
                    }
                    score_stack.Pop();
                }
            }
        }
        public void pop_time_score()
        {
            pop_time_score(bug_profile_time_type.get_current_tick());
        }

        public void begin_bug_time(long a_current_tick)
        {
            if (null != this)
            {
                if (0 == bug_scope_count++)
                {
                    bug_scope_begin_time = a_current_tick;
                }
            }
        }
        public void end_bug_time()
        {
            if (null != this)
            {
                if (0 == --bug_scope_count)
                {
                    if (0 < score_stack.Count)
                    {
                        score_stack.Peek().self_time_set.bug_time += bug_profile_time_type.get_current_tick() -bug_scope_begin_time;
                    }
                }
            }
        }
        
        protected void overall_scope_end()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();

            begin_bug_time(a_current_tick);
            pop_time_score();
            overall_time_score.self_time_set.whole_time = bug_profile_time_type.get_current_tick() -overall_start_time;
            var overall_message = new bug_message
            (
#if BUG_WITHOUT_LOCATION_INFO
#else
                "overall_scope_label", 0,
#if BUG_FUNCTION_NAME
                "overall_scope_label",
#endif
#endif
                "overall_scope_label"
            );
            add_time_score(overall_message, "overall_scope_label", overall_time_score);
            end_bug_time();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_bug_time_scope
    //

    class bug_bug_time_scope :IDisposable
    {
        bug_profiler profiler;
        public bug_bug_time_scope()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            profiler = bug_profiler.instance;
            if (null != profiler)
            {
                profiler.begin_bug_time(a_current_tick);
            }
        }
        public bug_bug_time_scope(long a_current_tick)
        {
            profiler = bug_profiler.instance;
            if (null != profiler)
            {
                profiler.begin_bug_time(a_current_tick);
            }
        }
        public void Dispose()
        {
            if (null != profiler)
            {
                profiler.end_bug_time();
            }
        }
    };
    
    
    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profile_scope
    //
    
    class bug_profile_scope :IDisposable
    {
        public bug_profiler profiler;
        public string start_stamp;
        public long start_time;
        public bug_profile_time_score time_score;
        public bug_message message;
        
        public bug_profile_scope(string a_message_value)
        {
#if BUG_WITHOUT_LOCATION_INFO
#else
            var call_stack = new StackFrame(1, true);
#endif
            bug_message a_message = new bug_message
            (
#if BUG_WITHOUT_LOCATION_INFO
#else
                call_stack.GetFileName(),
                call_stack.GetFileLineNumber(),
#if BUG_FUNCTION_NAME
                call_stack.GetMethod().Name,
#endif
#endif
                a_message_value
            );
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick))
            {
                profiler = bug_profiler.instance;

                start_stamp = last_stamp;
                start_time = a_current_tick;
                time_score = new bug_profile_time_score();
                message = new bug_message(a_message);

                profiler.push_time_score(time_score, a_current_tick);
            }
        }
        public bug_profile_scope(bug_message a_message)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick))
            {
                profiler = bug_profiler.instance;

                start_stamp = last_stamp;
                start_time = a_current_tick;
                time_score = new bug_profile_time_score();
                message = new bug_message(a_message);

                profiler.push_time_score(time_score, a_current_tick);
            }
        }
        public void Dispose()
        {
            long current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(current_tick))
            {
                if (null != profiler)
                {
                    profiler.pop_time_score(current_tick);
                }
                time_score.self_time_set.whole_time = current_tick -start_time -time_score.get_sub_time_set().get_whole_time().value;
                time_score.self_time_set.work_time = time_score.get_self_time_set().get_whole_time().value -time_score.get_self_time_set().get_bug_time().value;
                if (null != profiler)
                {
                    profiler.add_time_score(message, start_stamp, time_score);
                }
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  write
    //

    public static void write(bug_message text, IEnumerable<string> tags)
    {
        long a_current_tick = bug_profile_time_type.get_current_tick();
        using (var bug_time_scope = new bug_bug_time_scope(a_current_tick))
        {
            if (null != trace_writer)
            {
                trace_writer(text, tags);
            }
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_scope
    //

    class bug_scope : bug_profile_scope, IDisposable
    {
        public IEnumerable<string> tags;

        public bug_scope(bug_message a_message, IEnumerable<string> a_tags)
            :base(a_message)
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick)
            {
                tags = a_tags;
                write(message.create(string.Format("▽{0}", message.get_message())), a_tags);
                if (null != profiler)
                {
                    ++profiler.level;
                }
            }
        }
        public new void Dispose()
        {
            long a_current_tick = bug_profile_time_type.get_current_tick();
            using(var bug_time_scope = new bug_bug_time_scope(a_current_tick)
            {
                write(message.create(string.Format("△{0}", message.get_message())), tags);
                if (null != profiler)
                {
                    --profiler.level;
                }
            }
            base.Dispose();
        }
    }

}

2010-02-15

[][] C#バグベアード擬き プロファイルデータ構造部

とりあえずオリジナルのプロファイルデータ構造部をC#へ移植。

using System;
using System.Collections.Generic;
#if BUG_WITHOUT_LOCATION_INFO
#else
using System.Diagnostics;
#endif

public class bug_puppy
{
    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profile_time_type
    //
    
    class bug_profile_time_type
    {
        public long value;
        
        public bug_profile_time_type(long a_value)
        {
            value = a_value;
        }
        public bug_profile_time_type(bug_profile_time_type a)
        {
            value = a.value;
        }
        
        public static long get_current_tick()
        {
            return DateTime.Now.Ticks;
        }
        
        public static long get_tick_resolution()
        {
            return 1000000;
        }
        public long get_sec()
        {
            //return value /get_tick_resolution();
            return value / 1000000;
        }
        public long get_usec()
        {
            //const long tick_resolution = get_tick_resolution();
            //const long scale = 1000000;
            //return ((value %tick_resolution) *scale) /tick_resolution;
            return value % 1000000;
        }
        
        public string get_string(string a)
        {
            if (0 <= value)
            {
                return string.Format
                (
                    "{0}.{1:D6}",
                    get_sec().ToString(),
                    get_usec().ToString()
                );
            }
            else
            {
                return string.Format("-{0}", new bug_profile_time_type(-value).get_string(a));
            }
        }
        public bool less_than(bug_profile_time_type a)
        {
            return value < a.value;
        }
    }
    
    
    ///////////////////////////////////////////////////////////////////////////
    //
    //  bug_profile_time_set, bug_profile_time_score, bug_profile_time_score_set
    //
    
    class bug_profile_time_set
    {
    
        public long whole_time;
        public long bug_time;
        public long work_time;
        
        public bug_profile_time_set()
        {
            whole_time = 0;
            bug_time = 0;
            work_time = 0;
        }
        public bug_profile_time_set(bug_profile_time_set a)
        {
            assign(a);
        }
        
        public bug_profile_time_type get_whole_time()
        {
            return new bug_profile_time_type(whole_time);
        }
        public bug_profile_time_type get_bug_time()
        {
            return new bug_profile_time_type(bug_time);
        }
        public bug_profile_time_type get_work_time()
        {
            return new bug_profile_time_type(work_time);
        }
        
        public string get_string(string separator)
        {
            return
                get_whole_time().get_string(separator) + separator
                + get_bug_time().get_string(separator) + separator
                + get_work_time().get_string(separator);
        }
        
        public bug_profile_time_type get_core_value()
        {
            return get_work_time();
        }
        public bool less_than(bug_profile_time_set a)
        {
            return get_core_value().less_than(a.get_core_value());
        }

        public bug_profile_time_set assign(bug_profile_time_set a)
        {
            whole_time = a.whole_time;
            bug_time = a.bug_time;
            work_time = a.work_time;
            return this;
        }
        public bug_profile_time_set add(bug_profile_time_set a)
        {
            whole_time += a.whole_time;
            bug_time += a.bug_time;
            work_time += a.work_time;
            return this;
        }
        public bug_profile_time_set div(long a)
        {
            whole_time /= a;
            bug_time /= a;
            work_time /= a;
            return this;
        }
    }

    class bug_profile_time_score
    {
    
        public bug_profile_time_set self_time_set;
        public bug_profile_time_set sub_time_set;
        
        public bug_profile_time_score()
        {
            self_time_set = new bug_profile_time_set();
            sub_time_set = new bug_profile_time_set();
        }
        public bug_profile_time_score(bug_profile_time_score a)
        {
            self_time_set = new bug_profile_time_set(a.self_time_set);
            sub_time_set = new bug_profile_time_set(a.sub_time_set);
        }
        
        public bug_profile_time_set get_all_time_set()
        {
            var result = new bug_profile_time_set(self_time_set);
            result.bug_time += sub_time_set.bug_time;
            result.work_time += sub_time_set.work_time;
            return result;
        }
        public bug_profile_time_set get_self_time_set()
        {
            return self_time_set;
        }
        public bug_profile_time_set get_sub_time_set()
        {
            return sub_time_set;
        }

        public string get_string(string separator)
        {
            return
                get_all_time_set().get_string(separator) + separator
                + get_self_time_set().get_string(separator) + separator
                + get_sub_time_set().get_string(separator);
        }

        public bug_profile_time_set get_core_value()
        {
            return get_all_time_set();
        }
        public bool less_than(bug_profile_time_score a)
        {
            return get_core_value().less_than(a.get_core_value());
        }

        public bug_profile_time_score assign(bug_profile_time_score a)
        {
            self_time_set.assign(a.self_time_set);
            sub_time_set.assign(a.sub_time_set);
            return this;
        }
        public bug_profile_time_score add(bug_profile_time_score a)
        {
            self_time_set.add(a.self_time_set);
            sub_time_set.add(a.sub_time_set);
            return this;
        }
        public bug_profile_time_score div(long a)
        {
            self_time_set.div(a);
            sub_time_set.div(a);
            return this;
        }
    };

    class bug_profile_time_score_set
    {
        public bug_profile_time_score total_score;
        public string min_begin_stamp;
        public bug_profile_time_score min_score;
        public string max_begin_stamp;
        public bug_profile_time_score max_score;
        public long count;
        
        public bug_profile_time_score_set()
        {
            total_score = new bug_profile_time_score();
            min_score = new bug_profile_time_score();
            max_score = new bug_profile_time_score();
            count = 0;
        }
        public bug_profile_time_score_set(bug_profile_time_score_set a)
        {
            total_score = new bug_profile_time_score(a.total_score);
            min_score = new bug_profile_time_score(a.min_score);
            max_score = new bug_profile_time_score(a.max_score);
            count = a.count;
        }

        public bug_profile_time_score get_total_score()
        {
            return total_score;
        }
        public bug_profile_time_score get_min_score()
        {
            return min_score;
        }
        public bug_profile_time_score get_max_score()
        {
            return max_score;
        }
        public bug_profile_time_score get_average_score()
        {
            if (0 != count)
            {
                return new bug_profile_time_score(get_total_score()).div(get_count());
            }
            else
            {
                return get_total_score();
            }
        }
        public long get_count()
        {
            return count;
        }

        public string get_string(string separator)
        {
            return
                get_total_score().get_string(separator) + separator
                + get_count().ToString() + separator
                + get_average_score().get_string(separator) + separator
                + min_begin_stamp + separator
                + get_min_score().get_string(separator) + separator
                + max_begin_stamp + separator
                + get_max_score().get_string(separator);
        }
        
        public void add_score(string a_begin_stamp, bug_profile_time_score a_time_score)
        {
            if (0 == get_count())
            {
                total_score.assign(a_time_score);
                set_min_score(a_begin_stamp, a_time_score);
                set_max_score(a_begin_stamp, a_time_score);
            }
            else
            {
                total_score.add(a_time_score);

                if (a_time_score.less_than(min_score))
                {
                    set_min_score(a_begin_stamp, a_time_score);
                }
                if (max_score.less_than(a_time_score))
                {
                    set_max_score(a_begin_stamp, a_time_score);
                }
            }
            ++count;
        }
        
        private void set_min_score(string a_begin_stamp, bug_profile_time_score a_time_score)
        {
            min_begin_stamp = a_begin_stamp;
            min_score.assign(a_time_score);
        }
        private void set_max_score(string a_begin_stamp, bug_profile_time_score a_time_score)
        {
            max_begin_stamp = a_begin_stamp;
            max_score.assign(a_time_score);
        }
    }

    // 省略

}

2010-02-14

バグベアード

[][] バグベアードを更新しました。

http://tricklib.com/cxx/ex/bugbeard/

2010-02-14 以下の点を修正。
  • #include <sys\stat.h> を #include <sys/stat.h> に修正。(ご指摘、感謝)
  • 一部 BUT_T() が使用されていなかった箇所に BUT_T() を適用。(ご指摘、感謝)
  • bug_get_winver() を Windows 7 などにも対応した最新の状態に更新。
  • Boost.勉強会で発表したバグベアード入門の ustream へのリンクと発表資料の追加。

...Boost.勉強会の発表当日は.pptx版しか用意していなかった発表資料も.pdf版を用意しておきました。

2009-04-07

バグベアード

[][][][] `Д´)ノ バグベアード抜きで printf デバッグを語るんじゃねぇ!

わたしがprintf()デバッグをしない理由

...くそぅ、まだまだバグベアード( why バグベアード? )の知名度が足りねぇのか。

printf デバッグにおいてはバグベアードのようなモジュールを利用するかどうかで大きく話の前提が変わるんだけどなぁ。自分的には「この作者、頭おかしい!」と呼んでもらうに足るレベルの作り込み*1に達していると思ってんだけど、その存在を知ってもらってなけりゃそりゃお話にならんわな。('A`)


しかもこの人、 Debug Hacks の著者かよ。あの様子だとデバッグツールの紹介としても一言も触れられていないんだろうなぁ。バグベアードの存在はまさに Debug における Hack だと言うのに。


printf デバッグの是非について少し自分の意見を述べておきますと、多くの場合、printf デバッグはそれが場当たり的に行われるものである点が非常にまずいものだと考えています。ソースコードを修正する以上はデバッグの為の一時的な埋め込みであろうとプログラミングであることには変わりなく、プログラミングである以上は場当たり的に行うべきではありません。printf デバッグそのものに一長一短はあるにせよ「 printf デバッグ=悪」とするほどのものではなく、悪いのは「場当たり的に行われる printf デバッグ」かと。

*1プロファイリングカバレッジ測定の機能も有しています。

2008-11-01

Logicool Z-10

[][] バグベアードのサンプルコードを訂正しました。

http://tricklib.com/cxx/ex/bugbeard/

2008-11-01 以下の点を修正。
  • プロファイル&カバレッジ測定サンプル中の bug_tsv_profile_logger を bug_tsv_profiler に訂正。(間違っていたのはこのページ中の表記のみで、ダウンロード用の同サンプルのファイルは元から正しい記述である bug_tsv_profiler になっています。)

2008-09-23

バグベアード

[][] バグベアードを更新しました。(プロファイル対応、カバレッジ対応、他)

http://tricklib.com/cxx/ex/bugbeard/

2008-09-23 以下の点を修正。

  • プロファイル対応
  • カバレッジ対応
  • プロファイル&カバレッジのサンプルコードを追加。
  • bug_tsv_logger でヘッダー行を出力するように修正。
  • ヘッダー行の出力を抑止する指定マクロ(BUG_WITHOUT_TSV_LOG_HEADER, BUG_WITHOUT_TSV_PROFILE_HEADER, BUG_WITHOUT_TSV_COVERAGE_HEADER)の追加。
  • BUG_DISABLED_PSAPI指示マクロの追加( このマクロが定義されると bug_enum_module_version_info() の実装を行わない )。
  • QueryPerformance() の結果を秒+マイクロ秒単位へ変換して表示を行う bug_QueryPerformanceSecond_stamp の追加。
  • OSVERSIONINFOEX まわりで WINVER の判定が精確でなかった箇所の修正。
  • bug_logger::stamp を private に変更し、bug_logger::get_new_stamp(), bug_logger::get_last_stamp() を追加。
  • bug_drive_info() の出力に sectors-per-cluster と bytes-per-sector を追加。
  • BUG_DEFINE_GLOBAL_LOGGER と BUG_DEFINE_GLOBAL_PROFILER の追加。
  • bug_windows_system_info() の追加。
  • bug_file_hash() を追加。
  • bug_enum_module_hash() を追加。
  • bug_logger::get_instance() の追加および BUG_LOG マクロの修正(ただのリファクタリング)。
  • bug_logger::get_process_id() および bug_logger::get_thread_id() をクラスの外に出しに bug_get_process_id() および bug_get_thread_id() に変更(ただのリファクタリング)。
  • 不必要な #include <vector> を削除。
  • #pragma warning(disable:1011) は VC じゃなくて Intel ででる警告なので icc に限定。

...今回、いろいろ手を入れましたが、やはり一番大きいのはプロファイル対応とカバレッジ対応ですね。こちらの機能の使い方に関してはプロファイル&カバレッジ測定サンプルを参照して下さい。

プロファイルもカバレッジも癖が強い点にはご注意ください。プロファイルについてバグベアード独自のスコープについて把握する必要がありますし、カバレッジも if 文限定でしかも一切通過しかなかった if 文は列挙されませんし。ただ、他にプロファイリングツールやカバレッジ測定ツールを利用されていないのでしたら無いよりは確実にマシですし、これらのツールはその有る無しの差がとても大きな存在ですので癖の強いところを差し引いてもオススメに値すると考えています。

2008-06-05

バグベアード

[][] バグベアードを更新しました。

http://tricklib.com/cxx/ex/bugbeard/

2008-06-05 以下の点を修正。

  • VC でバグベアード適用時に過剰となる警告を抑止する為に #pragma warning(disable:1011) を追加。
  • bug_thread_local_storage::init() に base_type::set_target_storage() を含める。
  • g++ のバージョンによってはコンパイルエラーの原因になるので PTHREAD_MUTEX_INITIALIZER の使用を中止。( pthread_mutex_init() による初期化を行っているので元々不要な指定。 )
  • 現時点のバグベアードでは不要だが対称性の観点から bug_unlock クラスを追加。
  • ロケーション情報の除去オプション(BUG_WITHOUT_LOCATION_INFO)を追加。
  • switch の値が出力されないバグの解決。

...前回追加した BUG_MASK_SOURCECODE と今回追加した BUG_WITHOUT_LOCATION_INFO を両方指定するとログがかなりすっきりします。ただ、その分情報が随分と少なくなるので実用的かどうかはかなり怪しいです。(^^;

それからプアなコンパイラ上ではまだまだ不安定なのでプロファイラ機能やカーネルモード対応の前に安定化を図る予定です。

2008-04-17

[][] バグベアードを利用したプロファイリング

今現在、バグベアードを利用してプロファイリングをやろうなどと、輪をかけて馬鹿なことを考えているとこなんですが、実際のところ、いまのバグベアードに一切手を入れなくてもバグベアードによって出力されたログを解析するツールを用意するだけでプロファイリングできないことはないんですよね。

最初はバグベアードによるオーバーヘッドがかなりあるだろうからプロファイリングの為にはもう一ひねり必要かなとも考えていたのですが、市販のプロファイリングツールであってもプロファイラの為にシステムリソースがなんらかの形で喰われることには変わりが無く、結局のところ影響の程度問題の差に過ぎないんですよね。

で、実は今、お仕事のほうで弄ってるプログラムでテラ単位クラスのボリュームのデータを処理するものがあるんだけど、このプログラム、数十GiBクラスのデータなら特に問題ないんだけど、数百GiBクラス以上のボリュームのデータを処理してると極端にパフォーマンスが落ちちゃうんですよ。で、まぁ、パフォーマンスの問題ですから、まず最初にやるべきことはプロファイラでどこでなにがネックになっているのか調査するのが先決なんですがプロファイリングのデータが膨れ上がり過ぎてプロファイラがコケやがるんですよ。orz

そこで、話がバグベアードに戻るわけですがもっと出力する情報量を絞ったロガークラスとパイプへの出力を行うライタークラス、そしてそのデータを受け取ってプロファイリングデータを生成するプログラムを作れば結構イケてるものに仕上がるじゃないかなぁと。バグベアードによるオーバーヘッド分をどうするのかって問題はありますが、その点については簡潔主義に倣い最初はオーバーヘッドに対する処置は一切なしで様子を見てみようかと。

まぁ、お仕事のほうの問題は早急に片付けにゃならんので、測定用のコードをちまちまと手作業で埋め込むことでお茶を濁さざるを得ないんですが、バグベアードベースのプロファイラは今後の為にも用意しておこうかなと。

2008-04-01

[][] バグベアードを更新しました。

http://tricklib.com/cxx/ex/bugbeard/

2008-04-01 以下の点を修正。

  • BUG_MASK_SOURCECODE の追加。
  • "悪魔の契約" の「構文の制限」に "例外仕様構文" に関する記述を追記。

BUG_MASK_SOURCECODE に関しては...

このマクロが定義されているとステートメントハックによるログ出力中の条件式が "..." に置き換えられます。

...というもので、ログ出力量の軽減と、エンドユーザ環境でログ収集を行う際のエンドユーザに見られてしまうソースコードの軽減が図れます。

"例外仕様構文" に関しては、ステートメントハックを適用している箇所では例外仕様構文が使えないのにその記述が抜けていたので記述しました。

2008-03-10

[][] バグベアードを更新しました。

http://tricklib.com/cxx/ex/bugbeard/

2008-03-10 以下の点を修正。

  • "悪魔の契約" に「順序不安定」を追記。
  • bug_compact_tree_logger の追加。
  • インクルードの <sys\timeb.h> のパスを <sys/timeb.h> に修正。
  • 命名規則的に明らかにおかしいところ一部修正
    • BUG_SINT64_TYPE→bug_sint64_type
    • BUG_UINT64_TYPE→bug_uint64_type
    • BUG_OutputDebugString_writer→bug_OutputDebugString_writer
    • BUG_get_winver→bug_get_winver
    • run_string→bug_run_string
    • bug_short_clock_stamp_sx_with_date→bug_short_clock_stamp_with_date
  • bug_uni_logger を削除。( 既にその役目は bug_thread_local_storage に取って代わられているので。)

プログラム的な修正は以上の内容で、ドキュメントも以下のものを加筆しました。

why バグベアード?http://tricklib.com/cxx/ex/bugbeard/#why
リファレンスhttp://tricklib.com/cxx/ex/bugbeard/#reference

...あれから、いくつか評価を頂いているのですが総じて「微妙」な評価のようです。

その評価に対する自分の見解としては既存のデバッガによるデバッグスタイルとの違い...というかいままでの主流のスタイルとは異なるスタイルを採用しなければならない戸惑いがその根底にあるように受け止めています。ちょっと考えればわかることではあるのですが、あえて今回デバッガとの違いを「why バグベアード?」として加筆しましたので興味のある方はご一読ください。