--- Begin Message ---
- To: Debian Bug Tracking System <submit@bugs.debian.org>
- Subject: kdbg really slow + displays incorrect information
- From: Philip Ashmore <contact@philipashmore.com>
- Date: Fri, 03 Jun 2011 04:57:30 +0100
- Message-id: <20110603035730.3546.7779.reportbug@potemkin.home>
Package: kdbg
Version: 2.5.0-1
Severity: important
I'm trying to debug a program that uses the SpiderMonkey JavaScript engine - I
don't know if this is a factor.
I will attach the program itself.
You compile it with
g++ -O0 -g -Wall -o sudoku-solver $(pkg-config --cflags mozilla-js) \
$(pkg-config --libs mozilla-js) sudoku-solver.cpp
When you run
kdbg sudoku-solver
You will notice that the startup takes ages.
I'm using KDE Trinity so I can launch system guard and it tells me that gdb is
really busy.
After a few minutes kdbg finally shows the source code.
I have kdbg configured to hide itself until it hits a breakpoint or exception.
Set a breakpoint at line 763, 'cout << "Values";'
When you tell it to run, it minimizes for a few minutes until it hits the
breakpoint in what is a really trivial program that should be instantaneous.
The time kdbg takes seems to increase the more you restart it.
-- System Information:
Debian Release: wheezy/sid
APT prefers testing
APT policy: (500, 'testing'), (500, 'stable')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.38-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=en_IE.UTF-8, LC_CTYPE=en_IE.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Versions of packages kdbg depends on:
ii kdebase-runtime 4:4.4.5-1 runtime components from the offici
ii libc6 2.13-4 Embedded GNU C Library: Shared lib
ii libgcc1 1:4.6.0-2 GCC support library
ii libkdecore5 4:4.4.5-5 the KDE Platform Core Library
ii libkdeui5 4:4.4.5-5 the KDE Platform User Interface Li
ii libkio5 4:4.4.5-5 the Network-enabled File Managemen
ii libqt4-dbus 4:4.7.3-1 Qt 4 D-Bus module
ii libqt4-network 4:4.7.3-1 Qt 4 network module
ii libqt4-svg 4:4.7.3-1 Qt 4 SVG module
ii libqt4-xml 4:4.7.3-1 Qt 4 XML module
ii libqtcore4 4:4.7.3-1 Qt 4 core module
ii libqtgui4 4:4.7.3-1 Qt 4 GUI module
ii libstdc++6 4.6.0-2 The GNU Standard C++ Library v3
Versions of packages kdbg recommends:
ii gdb 7.2-1 The GNU Debugger
kdbg suggests no packages.
-- no debconf information
// Copyright (C) 2011 Philip Ashmore (contact@philipashmore.com)
// License: LGPLv3. See LICENSE.txt for the full license.
// (libc.info.gz)Memory-mapped I/O
// https://developer.mozilla.org/En/SpiderMonkey/JSAPI_User_Guide
// Release mode
// g++ -O3 -g -Wall -o sudoku-solver $(pkg-config --cflags mozilla-js) $(pkg-config --libs mozilla-js) sudoku-solver.cpp
// Debug mode
// g++ -O0 -g -Wall -o sudoku-solver $(pkg-config --cflags mozilla-js) $(pkg-config --libs mozilla-js) sudoku-solver.cpp
#include <sys/types.h>
#include <sys/mman.h>
#include <ftw.h>
#include <fcntl.h>
#include <string.h>
#include <iostream>
#include <iomanip>
#include <map>
#include <set>
using namespace std;
#include <jsapi.h>
typedef map< string, uintN > SolutionsMap;
SolutionsMap solutions;
string last_text, puzzle;
uint64_t permute_count = 0;
uint64_t solution_count = 0;
bool g_all = false, g_quiet = false;
namespace Sudoku {
class BoardItem {
public:
BoardItem(uintN n = 0) : m_data(n) {}
BoardItem & operator =(uintN x) { set_number(x, false); return *this; }
uintN number() const { return m_data & 15; }
bool given() const { return m_data & 16; }
void set_number(uintN num, bool given_) { m_data = num + (given_ ? 16 : 0); }
void set_given(bool b) { m_data = number() + (b ? 16 : 0); }
operator uintN() const { return number(); }
protected:
uintN m_data;
};
typedef BoardItem Board[9][9];
struct Row {
Row() : m_data()
{
for(uintN n = 0; n < 9; ++n)
m_data[n] = BoardItem();
}
Row(const Row & o)
: m_data(o.m_data)
{
for(uintN n = 0; n < 9; ++n)
m_data[n] = o.m_data[n];
}
Row & operator =(const Row & o)
{
for(uintN n = 0; n < 9; ++n)
m_data[n] = o.m_data[n];
return *this;
}
BoardItem & operator[](uintN n) { return m_data[n]; }
const BoardItem & operator[](uintN n) const { return m_data[n]; }
bool empty() const
{
uintN n;
for(n = 0; n < 9; ++n)
if(m_data[n])
return false;
return true;
}
inline uintN length() const
{
uintN n;
for(n = 0; n < 9; ++n)
if(!m_data[n])
break;
return n;
}
protected:
BoardItem m_data[9];
};
ostream & operator <<(ostream & s, const Row & r)
{
uintN len = r.length();
for(uintN n = 0; n < len; ++n) {
if(n)
s << ' ';
s << r[n];
}
return s;
}
struct stream_range
{
stream_range(const Row & r_, uintN m_)
: row(r_)
, mark(m_)
{}
const Row & row;
uintN mark;
};
ostream & operator <<(ostream & s, const stream_range & r)
{
uintN len = r.row.length();
for(uintN n = 0; n < len; ++n) {
if(n)
s << ' ';
if(n == r.mark)
s << '[';
s << r.row[n];
if(n == r.mark)
s << ']';
}
return s;
}
const Row row_all_filled()
{
Row r;
for(uintN n = 0; n < 9; ++n)
r[n] = n + 1;
return r;
}
const Row all_filled = row_all_filled();
class Solver
{
public:
Solver() : m_board() {}
virtual ~Solver() {}
virtual uint64_t count() = 0;
Board m_board;
};
template< bool all, bool quiet >
class SolverT : public Solver
{
public:
SolverT() : Solver() {}
Row filter_by_row(uintN x0, uintN y0, const Row & a0)
{
Row a1;
uintN a, x;
for(a = 0; a < 9; ++a) {
if(!a0[a])
continue;
for(x = 0; x < 9; ++x) {
if(x == x0)
continue;
if(m_board[x][y0] == a)
break;
}
if(x != 9)
continue;
a1[a] = a + 1;
}
//cout << "filter_by_row[" << x0 << ", " << y0 << "] returning [" << a1
// << ']' << endl;
return a1;
}
Row filter_by_column(uintN x0, uintN y0, const Row & a0)
{
Row a1;
uintN a, y;
for(a = 0; a < 9; ++a) {
if(!a0[a])
continue;
for(y = 0; y < 9; ++y) {
if(y == y0)
continue;
if(m_board[x0][y] == a)
break;
}
if(y != 9)
continue;
a1[a] = a + 1;
}
//cout << "filter_by_column[" << x0 << ", " << y0 << "] returning [" << a1
// << ']' << endl;
return a1;
}
Row filter_by_grid(uintN x0, uintN y0, const Row & a0)
{
Row a1;
uintN a, x, y, gx = (x0/3)*3, gy = (y0/3)*3;
for(a = 0; a < 9; ++a) {
if(!a0[a])
continue;
for(x = gx; x < (gx + 3); ++x) {
for(y = gy; y < (gy + 3); ++y) {
if((x == x0) && (y == y0))
continue;
if(m_board[x][y] == a)
break;
}
if(y != (gy + 3))
break;
}
if(x != (gx + 3))
continue;
a1[a] = a + 1;
}
//cout << "filter_by_grid[" << x0 << ", " << y0 << "] returning [" << a1
// << ']' << endl;
return a1;
}
struct BlankFinderResult {
BlankFinderResult(uintN x_ = 0, uintN y_ = 0, bool g_ = false)
: x(x_), y(y_), good(g_) {}
uintN x, y;
bool good;
};
BlankFinderResult first_blank(uintN x0, uintN y0)
{
uintN xn = x0;
for(uintN y = y0; y < 9; ++y) {
for(uintN x = xn; x < 9; ++x) {
if(!m_board[x][y])
return BlankFinderResult(x, y, true);
}
xn = 0;
}
return BlankFinderResult(0, 0, false);
}
BlankFinderResult next_blank(uintN x, uintN y)
{
if(x == 8) {
if(y == 8)
return BlankFinderResult(0, 0, false);
return first_blank(0, y+1);
}
return first_blank(x+1, y);
}
void permute_square(uintN level, uintN x, uintN y)
{
if(all) {
if(!quiet) {
++permute_count;
if(!(permute_count % 10000000)) {
cout << "#solutions " << solution_count
<< "\n==================\n";
dump_solution();
}
}
}
// Iterate through the valid entries for this square.
// If there are no valid entries then we're sunk.
Row range = filter_by_grid(x,y
, filter_by_row(x,y
, filter_by_column(x,y, all_filled)));
uintN rl = range.length();
if(!rl) {
//cout << '[' << setw(2) << level << "] no solutions possible\n"
//"==========================\n";
//dump_solution();
return; // No solutions possible.
}
uintN a;
if(!level) {
//this.worker.postMessage({ cmd : "range", value : range.length });
//this.worker.postMessage({ cmd : "update", value : 0 });
;
}
for(a = 0; a < rl; ++a) {
//for(uintN i = 0; i < level; ++i)
// cout << " ";
//cout << "[" << (x+1) << ", " << (y+1) << "] "
// << "-> " << stream_range(range, a) << endl;
if(!level) ;
//this.worker.postMessage({ cmd : "update", value : a });
m_board[x][y] = range[a];
//this.report();
BlankFinderResult ret = next_blank(x, y);
if(!ret.good) {
++solution_count;
if(!quiet) {
if(all) {
if(!(solution_count % 100000))
cout << '.' << flush;
}else{
cout << "solution\n==================\n";
dump_solution();
}
}
continue; // All filled.
}
permute_square(level + 1, ret.x, ret.y);
}
if(!level) ;
//this.worker.postMessage({ cmd : "update", value : a });
m_board[x][y] = 0;
//this.report();
}
uint64_t count_blanks()
{
uint64_t count = 0;
for(uintN x = 0; x < 9; ++x)
for(uintN y = 0; y < 9; ++y)
if(!m_board[x][y])
++count;
return count;
}
uint64_t count()
{
solution_count = 0;
cout << "Initial puzzle\n==================\n";
dump_solution();
if(!all) {
if(count_blanks() > 63) {
cerr << "too many blanks" << endl;
return 0;
}
}
if(!valid())
return 0;
BlankFinderResult ret = first_blank(0,0);
if(!ret.good)
return 1; // Already done.
permute_square(0, ret.x, ret.y);
//document.gSudokuBoard.m_pieces = backup;
//this.report();
return solution_count;
}
void dump_solution()
{
for(uintN y = 0; y < 9; ++y) {
//cout << '[' (9-y) << ']';
for(uintN x = 0; x < 9; ++x) {
uintN v = m_board[x][9-y-1].number();
if(v)
cout << ' ' << v;
else
cout << " ";
}
cout << '\n';
}
}
bool row_valid(uintN y)
{
BlankFinderResult found[9];
uintN x;
for(x = 0; x < 9; ++x) {
if(!m_board[x][y])
continue;
BlankFinderResult & loc = found[m_board[x][y]-1];
//cout << "Saw " << m_board[x][y] << " in "
// "(" << (x+1) << ", " << (y+1) << ")." << endl;
if(loc.good) {
cerr << "row_valid: number " << m_board[x][y]
<< " found in (" << (loc.x+1) << ", " << (loc.y+1) <<
") AND in (" << (x+1) << ", " << (y+1) << ")." << endl;
return false;
}
loc = BlankFinderResult(x, y, true);
//cout << "Noting " << m_board[x][y] << " in "
// "(" << (x+1) << ", " << (y+1) << ")." << endl;
}
return true;
}
bool column_valid(uintN x)
{
BlankFinderResult found[9];
uintN y;
for(y = 0; y < 9; ++y) {
if(!m_board[x][y])
continue;
BlankFinderResult & loc = found[m_board[x][y]-1];
if(loc.good) {
cerr << "column_valid: number " << m_board[x][y]
<< " found in (" << (loc.x+1) << ", " << (loc.y+1) <<
") AND in (" << (x+1) << ", " << (y+1) << ")." << endl;
return false;
}
loc = BlankFinderResult(x, y, true);
}
return true;
}
bool grid_valid(uintN x0, uintN y0)
{
BlankFinderResult found[9];
uintN x, y;
for(x = x0; x < (x0+3); ++x) {
for(y = y0; y < (y0+3); ++y) {
if(!m_board[x][y])
continue;
BlankFinderResult & loc = found[m_board[x][y]-1];
if(loc.good) {
cerr << "grid_valid: number " << m_board[x][y]
<< " found in (" << (loc.x+1) << ", " << (loc.y+1) <<
") AND in (" << (x+1) << ", " << (y+1) << ")." << endl;
return false;
}
loc = BlankFinderResult(x, y, true);
}
}
return true;
}
bool valid()
{
for(uintN y = 0; y < 9; ++y)
if(!row_valid(y))
return false;
for(uintN x = 0; x < 9; ++x)
if(!column_valid(x))
return false;
for(uintN x = 0; x < 3; ++x)
for(uintN y = 0; y < 3; ++y)
if(!grid_valid(x*3,y*3))
return false;
return true;
}
};
} // namespace Sudoku {
JSBool board(JSContext *cx, JSObject *pObj, uintN argc, jsval *argv, jsval *vp)
{
cout << "board" << endl;
(void)pObj;
if ((!argc) || (!JSVAL_IS_OBJECT(argv[0]))) {
cerr << "Failed to get board data." << endl;
return JS_FALSE;
}
JSObject * obj = JSVAL_TO_OBJECT(argv[0]);
if(!obj) {
cerr << "Board data isn't an object." << endl;
return JS_FALSE;
}
uintN n, rc;
Sudoku::Solver * psolver;
if(g_all) {
if(g_quiet)
psolver = new Sudoku::SolverT< true, true >;
else
psolver = new Sudoku::SolverT< true, false >;
}else{
if(g_quiet)
psolver = new Sudoku::SolverT< false, true >;
else
psolver = new Sudoku::SolverT< false, false >;
}
Sudoku::Solver & solver = * psolver;
for(n = 0; n < 9; ++n) {
char name[3];
cout << '[' << (n+1) << ']';
sprintf(name, "%u", n);
jsval numarr;
JSBool b = JS_GetProperty(cx, obj, name, & numarr);
if(!b) {
cerr << "\nFailed to get board data for number " << (n + 1) << '.'
<< endl;
return JS_FALSE;
}
if(!JSVAL_IS_OBJECT(numarr))
return JS_FALSE;
JSObject * numobj = JSVAL_TO_OBJECT(numarr);
if(!numobj) {
cerr << "\nNumber [" << (n+1) << "] object isn't an object."
<< endl;
return JS_FALSE;
}
for(rc = 0; rc < 81; ++rc) { // At most 81 squares.
char name[3];
sprintf(name, "%u", rc);
jsval numval;
// Any not-present property has a value of undefined.
JSBool b = JS_GetProperty(cx, numobj, name, & numval);
if(!b) {
cerr << "\nFailed to get board data[" << rc << "] for number "
<< (n + 1) << '.' << endl;
return JS_FALSE;
}
// Try all those that work.
uint32_t val, x, y;
// undefined -> uint32_t(0).
if(!JS_ConvertArguments(cx, 1, & numval, "u", &val) || !val)
break;
x = (val / 10) - 1; y = (val % 10) - 1;
cout << " " << (x+1) << (y+1);
solver.m_board[x][y] = n + 1;
}
cout << '\n';
}
solver.count();
solutions[puzzle] = solution_count;
delete psolver;
JS_SET_RVAL(cx, vp, JSVAL_VOID); /* return undefined */
return JS_TRUE;
}
JSBool text(JSContext *cx, JSObject *pObj, uintN argc, jsval *argv, jsval *vp)
{
(void)pObj;
(void)argv;
const char *cmd;
if (!JS_ConvertArguments(cx, argc, argv, "s", &cmd))
return JS_FALSE;
last_text = cmd;
//cout << "text(" << last_text << ')' << endl;
JS_SET_RVAL(cx, vp, JSVAL_VOID); /* return undefined */
return JS_TRUE;
}
JSBool noop(JSContext *cx, JSObject *pObj, uintN argc, jsval *argv, jsval *vp)
{
(void)pObj;
(void)argc;
(void)argv;
JS_SET_RVAL(cx, vp, JSVAL_VOID); /* return undefined */
//cout << "noop" << endl;
return JS_TRUE;
}
static JSFunctionSpec myjs_global_functions[] = {
JS_FS("clear", noop, 1, 0, 0),
JS_FS("text", text, 1, 0, 0),
JS_FS("board", board, 1, 0, 0),
JS_FS("delay", noop, 1, 0, 0),
JS_FS("number", noop, 1, 0, 0),
JS_FS("numbers", noop, 1, 0, 0),
JS_FS("l2r", noop, 1, 0, 0),
JS_FS("r2l", noop, 1, 0, 0),
JS_FS("b2t", noop, 1, 0, 0),
JS_FS("t2b", noop, 1, 0, 0),
JS_FS("slide", noop, 1, 0, 0),
JS_FS("sliders", noop, 1, 0, 0),
JS_FS("slideX", noop, 1, 0, 0),
JS_FS("slidersX", noop, 1, 0, 0),
JS_FS("textX", noop, 1, 0, 0),
JS_FS("numberX", noop, 1, 0, 0),
JS_FS("numbersX", noop, 1, 0, 0),
JS_FS("l2rX", noop, 1, 0, 0),
JS_FS("r2lX", noop, 1, 0, 0),
JS_FS("b2tX", noop, 1, 0, 0),
JS_FS("t2bX", noop, 1, 0, 0),
JS_FS_END
};
/* The class of the global object. */
static JSClass global_class =
{ "global"
, JSCLASS_GLOBAL_FLAGS
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub // JS_StrictPropertyStub
, JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
, JSCLASS_NO_OPTIONAL_MEMBERS
};
/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno,
message);
}
/* JS variables. */
JSRuntime *rt;
JSContext *cx;
JSObject *global;
string dir;
string puzzle_fn_name(const char * file)
{
const char * last_slash = strrchr(file, '/');
if(!last_slash)
return "no_slash";
const char * last_dot = strrchr(last_slash, '.');
if(!last_dot)
return "no_dot";
return string(last_slash + 1, last_dot);
}
int process_script(const char * file)
{
// Call function puzzlefn_eh20081122md()
puzzle = puzzle_fn_name(file);
if(g_all) {
if(puzzle != "empty")
return 0;
}else{
if(puzzle == "empty")
return 0;
}
int fd = open(file, O_RDONLY);
if(!fd)
return 1;
size_t length = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
char * src = (char *)mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
if(src == ((char *)-1)) {
cerr << "Couldn't mmap(" << file << ")." << endl;
return 1;
}
JSBool b = JS_EvaluateScript(/*JSContext * */cx, /*JSObject *obj*/global,
src, /*uintN */length, file,
/*uintN lineno*/1, /*jsval *rval*/0);
if(!b) {
cerr << "Executing script(" << file << ") failed." << endl;
munmap(src, length);
return 1;
}
munmap(src, length);
string call = string("puzzlefn_") + puzzle + "()";
cout << "Calling " << call << " for file(" << file << ")." << endl;
b = JS_EvaluateScript(/*JSContext * */cx, /*JSObject *obj*/global
, call.c_str(), /*uintN */call.length(), "<call>"
, /*uintN lineno*/1, /*jsval *rval*/0);
if(!b) {
cerr << "Executing call for file(" << file << ") failed." << endl;
return 1;
}
return 0;
}
set< string > to_process;
int process_dir_entry(const char * file, const struct stat * p, int type)
{
if(type != FTW_F)
return 0;
if(file[strlen(file)-1] == '~')
return 0; // Skip backups.
puzzle = puzzle_fn_name(file);
if(g_all) {
if(puzzle != "empty")
return 0;
}else{
if(puzzle == "empty")
return 0;
}
to_process.insert(file);
return 0;
}
int process_dir()
{
int ret = ftw(dir.c_str(), & process_dir_entry, 100);
if(ret)
return ret;
cout << to_process.size() << " files to process." << endl;
set< string >::const_iterator i = to_process.begin();
set< string >::const_iterator j = to_process.end();
for(; i != j; ++i) {
const string & file = *i;
cout << "Processing " << file << '{' << endl;
ret = process_script(file.c_str());
cout << "Processing " << file << "} " << ret << endl;
if(ret)
return ret;
}
return 0;
}
int Usage()
{
cerr << "Usage: sudoku-solver [-a] [-q] <dir>" << endl;
return 1;
}
int mainX(int argc, const char *argv[])
{
for(int narg = 1; narg < argc; ++narg) {
const char * arg = argv[narg];
if(strlen(arg) < 1)
return Usage();
if(arg[0] == '-') {
if(strlen(arg) < 2)
return Usage();
if(arg[1] == 'a')
g_all = true;
else if(arg[1] == 'q')
g_quiet = true;
else
return Usage();
}else{
if(dir.length())
return Usage();
dir = arg;
}
}
/* Create a JS runtime. */
rt = JS_NewRuntime(8L * 1024L * 1024L);
if (rt == NULL)
return 1;
/* Create a context. */
cx = JS_NewContext(rt, 8192);
if (cx == NULL)
return 1;
JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT /*| JSOPTION_METHODJIT*/);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, reportError);
/* Create the global object in a new compartment. */
//global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
//global = JS_NewGlobalObject(cx, &global_class, NULL);
global = JS_NewObject(cx, &global_class, NULL, NULL);
if (global == NULL)
return 1;
/* Populate the global object with the standard globals,
like Object and Array. */
if (!JS_InitStandardClasses(cx, global))
return 1;
/* Your application code here. This may include JSAPI calls
to create your own custom JS objects and run scripts. */
if (!JS_DefineFunctions(cx, global, myjs_global_functions))
return 1;
// Read in the scripts, one at a time, and print their solutions.
int ret = 0;
if(process_dir())
ret = 1;
/* Cleanup. */
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
cout << "Summary." << endl;
cout << "Name Count" << endl;
cout << "==================== =====" << endl;
SolutionsMap::const_iterator i = solutions.begin();
SolutionsMap::const_iterator j = solutions.end();
for(; i != j; ++i)
cout << left << setw(20) << i->first << ' ' << right << setw(5)
<< i->second << endl;
return ret;
}
int main(int argc, const char *argv[])
{
(void)argc;
(void)argv;
Sudoku::Row row;
cout << "Values";
for(int n = 0; n < 9; ++n)
cout << ' ' << uintN(row[n]);
cout << endl;
return 0;
}
--- End Message ---