[m-rev.] for review: make the deep profiler work again
Zoltan Somogyi
zs at cs.mu.OZ.AU
Mon Nov 18 15:14:35 AEDT 2002
On 17-Nov-2002, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> POSIX guarantees that those will be macros, so a configure test isn't
> needed -- you can just use
>
> #ifdef O_CREAT
>
> rather than
>
> #ifdef MR_HAVE_O_CREAT
I decided to make centralize all feature tests in configure.in.
Here is an interdiff, containing both the changes I made in response to review
comments and the changes Fergus and I made together to update the installation
mechanisms of the deep profiler.
Zoltan.
diff -u Mmakefile Mmakefile
--- Mmakefile 12 Nov 2002 14:43:13 -0000
+++ Mmakefile 14 Nov 2002 07:25:53 -0000
@@ -349,6 +349,8 @@
#-----------------------------------------------------------------------------#
+# The code of the install rule is duplicated in bindist/bindist.Makefile.in.
+
.PHONY: install
install: install_main install_grades
@echo
@@ -358,9 +360,11 @@
@echo "-- $(INSTALL_MAN_DIR) to your MANPATH,"
@echo "-- and $(INSTALL_INFO_DIR) to your INFOPATH,"
@if test $(ENABLE_DEEP_PROFILER) != yes || \
- cmp -s scripts/mdprof.in $(INSTALL_CGI_DIR)/mdprof; \
+ cmp -s deep_profiler/mdprof_cgi \
+ $(INSTALL_CGI_DIR)/mdprof_cgi; \
then true ; else \
- echo "-- to copy scripts/mdprof to $(INSTALL_CGI_DIR),"; \
+ echo "-- to copy deep_profiler/mdprof_cgi" \
+ "to $(INSTALL_CGI_DIR),"; \
fi
@echo "-- and to add the following lines to the \`.emacs' file"
@echo "-- in your home directory:"
@@ -563,6 +567,7 @@
.PHONY: uninstall
uninstall:
+cd scripts; $(SUBDIR_MMAKE) uninstall
+ +cd deep_profiler; $(SUBDIR_MMAKE) uninstall
+cd util; $(SUBDIR_MMAKE) uninstall
+cd doc; $(SUBDIR_MMAKE) uninstall
-rm -r $(INSTALL_LIBDIR)
diff -u configure.in configure.in
--- configure.in 12 Nov 2002 02:58:51 -0000
+++ configure.in 18 Nov 2002 02:35:58 -0000
@@ -1443,6 +1443,38 @@
fi
AC_SUBST(MR_LITTLE_ENDIAN)
#-----------------------------------------------------------------------------#
+AC_MSG_CHECKING(whether we can use files as locks)
+AC_CACHE_VAL(mercury_cv_have_ocreat_oexcl,
+ AC_TRY_COMPILE([
+ #ifdef MR_HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+ #ifdef MR_HAVE_SYS_STAT_H
+ #include <sys/stat.h>
+ #endif
+ #ifdef MR_HAVE_FCNTL_H
+ #include <fcntl.h>
+ #endif
+ ],
+ [
+ #if defined(O_CREAT) && defined(O_EXCL)
+
+ #else
+ /*
+ ** As these macros are not defined the compilation must fail.
+ ** Unmatched brackets should do that for us.
+ */
+ }
+ #endif
+ ],
+ [mercury_cv_have_ocreat_oexcl=yes],
+ [mercury_cv_have_ocreat_oexcl=no])
+)
+AC_MSG_RESULT($mercury_cv_have_ocreat_oexcl)
+if test "$mercury_cv_have_ocreat_oexcl" = yes; then
+ AC_DEFINE(MR_HAVE_OCREAT_OEXCL)
+fi
+#-----------------------------------------------------------------------------#
AC_MSG_CHECKING(return values of system)
AC_CACHE_VAL(mercury_cv_normal_system_retval,
AC_TRY_RUN([
@@ -1838,18 +1870,21 @@
enable_deep_profiler="$enableval",enable_deep_profiler=default)
AC_MSG_CHECKING(whether to enable the deep profiler)
- # This test may need to be made more specific at a later date.
- # Currently it only distinguishes between systems which have
- # unistd.h or not, but at a later date we may also need to test for
- # other posix features.
-if test "$MR_HAVE_UNISTD_H" = 1 && \
+# We test for all the features needed by the deep profiler.
+if test "$MR_HAVE_SYS_TYPES_H" = 1 && \
+ test "$MR_HAVE_SYS_STAT_H" = 1 && \
+ test "$MR_HAVE_FCNTL_H" = 1 && \
+ test "$MR_HAVE_UNISTD_H" = 1 && \
test "$MR_HAVE_DIRENT_H" = 1 && \
test "$ac_cv_func_getpid" = yes && \
+ test "$ac_cv_func_fork" = yes && \
test "$ac_cv_func_opendir" = yes && \
test "$ac_cv_func_readdir" = yes && \
- test "$ac_cv_func_closedir" = yes
+ test "$ac_cv_func_closedir" = yes && \
+ test "$mercury_cv_have_ocreat_oexcl" = yes
then
mercury_cv_can_enable_deep_profiler=yes
+ AC_DEFINE(MR_DEEP_PROFILER_ENABLED)
else
mercury_cv_can_enable_deep_profiler=no
fi
diff -u deep_profiler/DESIGN deep_profiler/DESIGN
--- deep_profiler/DESIGN 11 Nov 2002 05:39:50 -0000
+++ deep_profiler/DESIGN 15 Nov 2002 05:30:59 -0000
@@ -110,6 +110,22 @@
fi
fi
+The pseudocode of the timeout handler:
+
+ try to get mutual exclusion (i.e. create mutex file)
+ if we got mutual exclusion
+ check whether any want files exist
+ if some do
+ abort the timeout
+ else
+ clean up, deleting the mutex file last
+ exit
+ fi
+ else
+ some client has the lock, they need a server,
+ so abort the timeout
+ fi
+
The initial design of the deep profiler had two separate programs. The old
mdprof_cgi was strictly a client: it *always* sent the query to a process
running the other program, mdprof_server. The problem with this approach
diff -u deep_profiler/Mercury.options deep_profiler/Mercury.options
--- deep_profiler/Mercury.options 13 Nov 2002 22:52:54 -0000
+++ deep_profiler/Mercury.options 15 Nov 2002 05:31:30 -0000
@@ -19,11 +19,13 @@
# We therefore turn off this optimization in all modules that may deal
# with arrays. This should not cause any performance problem, since there
# are no known duplicate calls in any performance critical predicates.
+#
+# XXX These flags should be deleted when the problem is fixed.
MCFLAGS-array_util = --no-optimize-duplicate-calls
MCFLAGS-callgraph = --no-optimize-duplicate-calls
MCFLAGS-canonical = --no-optimize-duplicate-calls
-MCFLAGS-clique = --no-optimize-duplicate-calls
+MCFLAGS-cliques = --no-optimize-duplicate-calls
MCFLAGS-dense_bitset = --no-optimize-duplicate-calls
MCFLAGS-exclude = --no-optimize-duplicate-calls
MCFLAGS-html_format = --no-optimize-duplicate-calls
diff -u deep_profiler/Mmakefile deep_profiler/Mmakefile
--- deep_profiler/Mmakefile 12 Nov 2002 13:03:05 -0000
+++ deep_profiler/Mmakefile 14 Nov 2002 07:37:02 -0000
@@ -20,7 +20,7 @@
MAIN_TARGET=all
MERCURY_MAIN_MODULES=mdprof_cgi mdprof_test
DEPEND=mdprof_cgi.depend mdprof_test.depend
- INSTALL=install_deep
+ INSTALL=install_cgi_progs
else
MAIN_TARGET=nothing
MERCURY_MAIN_MODULES=
@@ -113,9 +113,34 @@
# We don't install mdprof_test, since it is not for users.
-.PHONY: install_deep
-install_deep: mdprof_cgi
- -[ -d $(INSTALL_MERC_BIN_DIR) ] || mkdir -p $(INSTALL_MERC_BIN_DIR)
- cp `vpath_find mdprof_cgi$(EXT_FOR_EXE)` \
- $(INSTALL_MERC_BIN_DIR)/mdprof_cgi
+# The code of the install_cgi_progs target is duplicated in
+# bindist/bindist.Makefile.in, though the two rules refer to mdprof_cgi
+# by different paths.
+
+.PHONY: install_cgi_progs
+install_cgi_progs: mdprof_cgi
+ # $(INSTALL_CGI_DIR) is likely to be writeable only by root or
+ # the www system administrator, which is why we don't consider a
+ # failure of this action to be an error. If the command fails,
+ # the install action in ../Mmakefile will remind the user to do
+ # the copy later.
+ #
+ # The mv before the cp is there in case the executable is being
+ # executed when we do the install. The mv is of course expected to
+ # fail during a first-time installation.
+ -if test $(ENABLE_DEEP_PROFILER) = yes ; then \
+ mv $(INSTALL_CGI_DIR)/mdprof_cgi \
+ $(INSTALL_CGI_DIR)/mdprof_cgi.was ; \
+ cp mdprof_cgi $(INSTALL_CGI_DIR) ; \
+ fi
+
+uninstall:
+ # We try to uninstall mdprof_cgi, but failure to do so is not an
+ # error for two reasons: because we may simply lack permission to
+ # update the directory, and because the deep profiler installation
+ # may not have been enabled in the first place. (Looking at the current
+ # value of $(ENABLE_DEEP_PROFILER) to check for the latter wouldn't
+ # necessarily do any good, since its setting may have changed since
+ # the original install.)
+ -rm $(INSTALL_CGI_DIR)/mdprof_cgi
#-----------------------------------------------------------------------------#
diff -u deep_profiler/conf.m deep_profiler/conf.m
--- deep_profiler/conf.m 13 Nov 2002 10:51:40 -0000
+++ deep_profiler/conf.m 16 Nov 2002 12:31:41 -0000
@@ -46,28 +46,28 @@
( { Res1 = ok(0) } ->
io__open_input(TmpFile, TmpRes),
( { TmpRes = ok(TmpStream) } ->
- io__read_file(TmpStream, TmpReadRes),
- { TmpReadRes = ok(ServerNameChars0) ->
+ io__read_file_as_string(TmpStream, TmpReadRes),
+ {
+ TmpReadRes = ok(ServerNameNl),
(
- list__remove_suffix(ServerNameChars0,
- ['\n'], ServerNameChars)
+ string__remove_suffix(ServerNameNl,
+ "\n", ServerNamePrime)
->
- string__from_char_list(
- ServerNameChars, ServerName)
+ ServerName = ServerNamePrime
;
error("malformed server name")
)
;
+ TmpReadRes = error(_, _),
error("cannot read server's name")
},
io__close_input(TmpStream)
;
- { error("cannot open file to out the server's name") }
+ { error("cannot open file to find the server's name") }
),
- { RmTmpCmd = string__format("rm %s", [s(TmpFile)]) },
- io__call_system(RmTmpCmd, _)
+ io__remove_file(TmpFile, _)
;
- { error("cannot execute cmd to find out the server's name") }
+ { error("cannot execute cmd to find the server's name") }
).
:- pred mkfifo_cmd(string::out) is det.
@@ -92,7 +92,7 @@
:- pragma foreign_decl("C",
"
-#ifdef MR_HAVE_UNISTD_H
+#ifdef MR_DEEP_PROFILER_ENABLED
#include <sys/types.h>
#include <unistd.h>
#endif
@@ -103,14 +103,8 @@
[will_not_call_mercury, promise_pure],
"
-#if defined(MR_HAVE_UNISTD_H) && defined(MR_HAVE_GETPID)
+#ifdef MR_DEEP_PROFILER_ENABLED
Pid = getpid();
#else
- /*
- ** If MR_HAVE_GETPID is not defined, the deep profiler is not enabled
- ** anyway, so what the code here does doesn't matter. We still want to
- ** make it compile cleanly, though.
- */
-
- Pid = 0;
+ MR_fatal_error(""the deep profiler is not supported"");
#endif
").
diff -u deep_profiler/interface.m deep_profiler/interface.m
--- deep_profiler/interface.m 13 Nov 2002 17:11:16 -0000
+++ deep_profiler/interface.m 14 Nov 2002 06:59:44 -0000
@@ -474,7 +474,7 @@
machine_datafile_cmd_pref_to_url(Machine, DataFileName, Cmd, Preferences) =
"http://" ++
Machine ++
- "/cgi-bin/mdprof?" ++
+ "/cgi-bin/mdprof_cgi?" ++
cmd_to_string(Cmd) ++
string__char_to_string(query_separator_char) ++
preferences_to_string(Preferences) ++
diff -u deep_profiler/mdprof_cgi.m deep_profiler/mdprof_cgi.m
--- deep_profiler/mdprof_cgi.m 13 Nov 2002 22:06:59 -0000
+++ deep_profiler/mdprof_cgi.m 18 Nov 2002 02:54:56 -0000
@@ -24,7 +24,7 @@
:- import_module bool, char, string, int, array, list, set.
:- import_module require, std_util, getopt.
-:- import_module int, string, list, array, map, exception, require.
+:- import_module int, string, list, array, map, exception, require, library.
% The web server should always set QUERY_STRING. It may also pass its contents
% as arguments, but if any characters specials to the shell occur in the query,
@@ -69,7 +69,7 @@
:- pred process_command_line(io__state::di, io__state::uo) is cc_multi.
process_command_line -->
- io__progname_base("mdprof_cgi", ProgName),
+ io__progname_base(mdprof_cgi_progname, ProgName),
io__command_line_arguments(Args0),
% io__write_string("Args0: "),
% io__write_list(Args0, " ", write_bracketed_string),
@@ -78,7 +78,25 @@
Args0, Args, MaybeOptions) },
(
{ MaybeOptions = ok(Options) },
- process_args(Args, Options)
+ { lookup_bool_option(Options, help, Help) },
+ { lookup_bool_option(Options, version, Version) },
+ (
+ { Help = yes },
+ write_help_message(ProgName)
+ ;
+ { Help = no }
+ ),
+ (
+ { Version = yes },
+ write_version_message(ProgName)
+ ;
+ { Version = no }
+ ),
+ ( { Help = no, Version = no } ->
+ process_args(ProgName, Args, Options)
+ ;
+ []
+ )
;
{ MaybeOptions = error(Msg) },
io__set_exit_status(1),
@@ -86,10 +104,37 @@
[s(ProgName), s(Msg)])
).
-:- pred process_args(list(string)::in, option_table::in,
+:- func mdprof_cgi_progname = string.
+
+mdprof_cgi_progname = "mdprof_cgi".
+
+:- pred write_version_message(string::in, io__state::di, io__state::uo) is det.
+
+write_version_message(ProgName) -->
+ { library__version(Version) },
+ io__write_string(ProgName),
+ io__write_string(": Mercury deep profiler"),
+ io__nl,
+ io__write_string(Version),
+ io__nl.
+
+:- pred write_help_message(string::in, io__state::di, io__state::uo) is det.
+
+write_help_message(ProgName) -->
+ % The options are deliberately not documented; they change
+ % quite rapidly, based on the debugging needs of the moment.
+ % The optional filename argument is also for implementors only.
+ io__format("Usage: %s\n", [s(ProgName)]),
+ io__format("This program doesn't expect any arguments;\n", []),
+ io__format("instead it decides what to do based on the\n", []),
+ io__format("QUERY_STRING environment variable.\n", []).
+
+%-----------------------------------------------------------------------------%
+
+:- pred process_args(string::in, list(string)::in, option_table::in,
io__state::di, io__state::uo) is cc_multi.
-process_args(Args, Options) -->
+process_args(ProgName, Args, Options) -->
( { Args = [FileName] } ->
% Although this mode of usage is not intended for production
% use, allowing the filename and a limited range of commands
@@ -98,19 +143,20 @@
process_query(default_cmd(Options), no, FileName, Options)
;
io__set_exit_status(1),
- % The options are deliberately not documented; they change
- % quite rapidly, based on the debugging needs of the moment.
- io__write_string("Usage: mdprof_cgi [filename]\n"),
- io__write_list(Args, " ", write_bracketed_string)
+ write_help_message(ProgName)
+ % io__write_list(Args, " ", write_bracketed_string)
).
-:- pred write_bracketed_string(string::in, io__state::di, io__state::uo)
- is det.
-
-write_bracketed_string(S) -->
- io__write_string("<"),
- io__write_string(S),
- io__write_string(">").
+% This predicate is for debugging the command line given to mdprof_cgi by the
+% web server, should that be necessary
+%
+% :- pred write_bracketed_string(string::in, io__state::di, io__state::uo)
+% is det.
+%
+% write_bracketed_string(S) -->
+% io__write_string("<"),
+% io__write_string(S),
+% io__write_string(">").
:- pred write_html_header(io__state::di, io__state::uo) is det.
@@ -194,8 +240,7 @@
% Leave the response file to be examined.
;
{ Debug = no },
- { RmCmd = string__format("rm %s", [s(ResponseFileName)]) },
- io__call_system(RmCmd, _)
+ io__remove_file(ResponseFileName, _)
).
% Handle the given query and then become the new server. Delete the mutex
@@ -223,7 +268,7 @@
{ StartupStreamRes = error(_) },
{ error("cannot create startup file") }
)
- ;
+ ;
{ RecordStartup = no },
{ MaybeStartupStream = no }
),
@@ -240,7 +285,7 @@
% be flushed twice, once by the parent process and
% once by the child process.
io__flush_output(StartupStream1)
- ;
+ ;
{ MaybeStartupStream = no }
),
(
@@ -308,7 +353,17 @@
% want to duplicate them. We also don't want to delete
% the pipes we need or the startup file.
unregister_file_for_cleanup(MutexFile),
- unregister_file_for_cleanup(WantFile)
+ unregister_file_for_cleanup(WantFile),
+ io__stdin_stream(StdIn),
+ io__close_input(StdIn),
+ io__stdout_stream(StdOut),
+ io__close_output(StdOut),
+ io__stderr_stream(StdErr),
+ io__close_output(StdErr),
+ io__current_binary_input_stream(BinaryStdIn),
+ io__close_binary_input(BinaryStdIn),
+ io__current_binary_output_stream(BinaryStdOut),
+ io__close_binary_output(BinaryStdOut)
;
{ ChildHasParent = child_has_no_parent },
% We don't actually have a parent process, so we need
@@ -460,18 +515,13 @@
%-----------------------------------------------------------------------------%
:- pragma foreign_decl("C", "
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-").
-
-:- pragma foreign_decl("C", "
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+#ifdef MR_DEEP_PROFILER_ENABLED
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+#endif
").
:- pred check_for_existing_fifos(string::in, string::in, int::out,
@@ -482,6 +532,7 @@
S0::di, S::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
struct stat statbuf;
int status;
@@ -496,6 +547,9 @@
}
S = S0;
+#else
+ MR_fatal_error(""deep profiling not enabled"");
+#endif
").
:- type child_has_parent
@@ -537,6 +591,7 @@
raw_detach_process(ResCode::out, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"{
+#ifdef MR_DEEP_PROFILER_ENABLED
pid_t status;
fflush(stdout);
@@ -548,15 +603,22 @@
ResCode = 1;
} else {
#ifdef MR_HAVE_SETPGID
- /* detach the server process from the parent's process group */
+ /*
+ ** Try to detach the server process from the parent's process
+ ** group, in case it uses the number of processes in the
+ ** process group to decide when the cgi `script' is done
+ */
setpgid(0, 0);
#else
- /* hope that web server doesn't depend on the process group */
+ /* Hope that web server doesn't depend on the process group. */
#endif
ResCode = 0;
}
S = S0;
+#else
+ MR_fatal_error(""deep profiling not enabled"");
+#endif
}").
%-----------------------------------------------------------------------------%
@@ -566,6 +628,7 @@
; clique
; debug
; detach_process
+ ; help
; modules
; proc
; quit
@@ -574,6 +637,7 @@
; record_loop
; server_process
; timeout
+ ; version
; write_query_string.
:- type options ---> options.
@@ -598,6 +662,7 @@
long("clique", clique).
long("debug", debug).
long("detach-process", detach_process).
+long("help", help).
long("modules", modules).
long("proc", proc).
long("quit", quit).
@@ -606,6 +671,7 @@
long("record-loop", record_loop).
long("server-process", server_process).
long("timeout", timeout).
+long("version", version).
long("write-query-string", write_query_string).
:- pred defaults(option::out, option_data::out) is nondet.
@@ -620,6 +686,7 @@
defaults0(clique, int(0)).
defaults0(debug, bool(no)).
defaults0(detach_process, bool(yes)).
+defaults0(help, bool(no)).
defaults0(modules, bool(no)).
defaults0(proc, int(0)).
defaults0(quit, bool(no)).
@@ -628,6 +695,7 @@
defaults0(record_startup, bool(yes)).
defaults0(server_process, bool(yes)).
defaults0(timeout, int(30)).
+defaults0(version, bool(no)).
defaults0(write_query_string, bool(yes)).
:- func default_cmd(option_table) = cmd.
diff -u deep_profiler/mdprof_test.m deep_profiler/mdprof_test.m
--- deep_profiler/mdprof_test.m 12 Nov 2002 13:00:30 -0000
+++ deep_profiler/mdprof_test.m 16 Nov 2002 15:10:15 -0000
@@ -22,34 +22,33 @@
:- import_module bool, char, string, int, array, list, set.
:- import_module require, std_util, getopt.
-:- import_module int, string, list, array, exception, require.
+:- import_module int, string, list, array, exception, require, library.
main -->
- io__progname_base("mdprof_tool", ProgName),
+ io__progname_base("mdprof_test", ProgName),
io__command_line_arguments(Args0),
{ getopt__process_options(option_ops(short, long, defaults),
Args0, Args, MaybeOptions) },
(
{ MaybeOptions = ok(Options) },
- ( { Args = [FileName] } ->
- { lookup_bool_option(Options, canonical_clique,
- Canonical) },
- server_name(Machine),
- read_and_startup(Machine, [FileName], Canonical, no,
- Res),
- (
- { Res = ok(Deep) },
- main2(Options, Deep)
- ;
- { Res = error(Error) },
- io__set_exit_status(1),
- io__format("%s: error reading data file: %s\n",
- [s(ProgName), s(Error)])
- )
+ { lookup_bool_option(Options, help, Help) },
+ { lookup_bool_option(Options, version, Version) },
+ (
+ { Help = yes },
+ write_help_message(ProgName)
;
- io__set_exit_status(1),
- io__format("Usage: %s [options*] filename\n",
- [s(ProgName)])
+ { Help = no }
+ ),
+ (
+ { Version = yes },
+ write_version_message(ProgName)
+ ;
+ { Version = no }
+ ),
+ ( { Help = no, Version = no } ->
+ main2(ProgName, Args, Options)
+ ;
+ []
)
;
{ MaybeOptions = error(Msg) },
@@ -58,19 +57,62 @@
[s(ProgName), s(Msg)])
).
-:- pred main2(option_table::in, deep::in, io__state::di, io__state::uo)
- is cc_multi.
+:- pred main2(string::in, list(string)::in, option_table::in,
+ io__state::di, io__state::uo) is cc_multi.
-main2(Options, Deep) -->
- { lookup_bool_option(Options, test, Test) },
- (
- { Test = no }
+main2(ProgName, Args, Options) -->
+ ( { Args = [FileName] } ->
+ { lookup_bool_option(Options, canonical_clique, Canonical) },
+ server_name(Machine),
+ read_and_startup(Machine, [FileName], Canonical, no, Res),
+ (
+ { Res = ok(Deep) },
+ { lookup_bool_option(Options, test, Test) },
+ (
+ { Test = no }
+ ;
+ { Test = yes },
+ { lookup_string_option(Options, test_dir,
+ TestDir) },
+ test_server(TestDir, default_preferences, Deep)
+ )
+ ;
+ { Res = error(Error) },
+ io__set_exit_status(1),
+ io__format("%s: error reading data file: %s\n",
+ [s(ProgName), s(Error)])
+ )
;
- { Test = yes },
- { lookup_string_option(Options, test_dir, TestDir) },
- test_server(TestDir, default_preferences, Deep)
+ io__set_exit_status(1),
+ write_help_message(ProgName)
).
+:- pred write_version_message(string::in, io__state::di, io__state::uo) is det.
+
+write_version_message(ProgName) -->
+ { library__version(Version) },
+ io__write_string(ProgName),
+ io__write_string(": Mercury deep profiler"),
+ io__nl,
+ io__write_string(Version),
+ io__nl.
+
+:- pred write_help_message(string::in, io__state::di, io__state::uo) is det.
+
+write_help_message(ProgName) -->
+ io__format("Usage: %s [<options>] <filename>\n", [s(ProgName)]),
+ io__format("<filename> must name a deep profiling data file.\n", []),
+ io__format("You should specify one of the following options:\n", []),
+ io__format("--help Generate this help message.", []),
+ io__format("--version Report the program's version number.", []),
+ io__format("--test Test the deep profiler, generating all\n", []),
+ io__format(" possible web pages of the popular types.", []),
+ io__format("You may also specify the following options:.", []),
+ io__format("--test-dir <dirname>\n", []),
+ io__format(" Put the generated web pages into <dirname>.\n",
+ []).
+ % --canonical-clique is not documented because it is not yet supported
+
%-----------------------------------------------------------------------------%
:- pred test_server(string::in, preferences::in, deep::in,
@@ -117,11 +159,13 @@
% file may contain hundreds of thousands of cliques. We therefore put
% each batch of pages in a different subdirectory, thus limiting the
% number of files/subdirs in each directory.
+ %
+ % XXX consider splitting up this predicate
{ Bunch = (Num - 1) // 1000 },
{ string__format("%s/%s_%04d",
[s(DirName), s(BaseName), i(Bunch)], BunchName) },
( { (Num - 1) rem 1000 = 0 } ->
- { string__format("test -p %s || mkdir -p %s",
+ { string__format("test -d %s || mkdir -p %s",
[s(BunchName), s(BunchName)], Cmd) },
io__call_system(Cmd, _)
;
@@ -147,8 +191,10 @@
:- type option
---> canonical_clique
; flat
+ ; help
; test
- ; test_dir.
+ ; test_dir
+ ; version.
:- type options ---> options.
:- type option_table == (option_table(option)).
@@ -162,8 +208,10 @@
:- pred long(string::in, option::out) is semidet.
long("canonical-clique", canonical_clique).
+long("help", help).
long("test", test).
long("test-dir", test_dir).
+long("version", version).
:- pred defaults(option::out, option_data::out) is nondet.
@@ -175,6 +223,8 @@
defaults0(canonical_clique, bool(no)).
+defaults0(help, bool(no)).
defaults0(test, bool(no)).
defaults0(test_dir, string("deep_test")).
+defaults0(version, bool(no)).
%-----------------------------------------------------------------------------%
diff -u deep_profiler/startup.m deep_profiler/startup.m
--- deep_profiler/startup.m 13 Nov 2002 16:17:33 -0000
+++ deep_profiler/startup.m 18 Nov 2002 02:57:03 -0000
@@ -29,7 +29,7 @@
:- import_module profile, read_profile, callgraph, canonical.
:- import_module measurements, array_util.
:- import_module std_util, int, string, array, assoc_list, set, map, require.
-:- import_module unsafe.
+% :- import_module unsafe.
read_and_startup(Machine, DataFileNames, Canonical, MaybeOutputStream, Res) -->
(
@@ -224,7 +224,6 @@
initialize_module_data(_ModuleName, PSPtrs) =
module_data(zero_own_prof_info, zero_inherit_prof_info, PSPtrs).
-
%-----------------------------------------------------------------------------%
:- pred record_css_containers_module_procs(int::in, proc_static::in,
@@ -868,8 +867,14 @@
:- pred maybe_report_stats(maybe(io__output_stream)::in,
io__state::di, io__state::uo) is det.
-maybe_report_stats(yes(_)) --> [].
- % io__report_stats("standard"). XXX
+% XXX: io__report_stats writes to stderr, which mdprof_cgi has closed.
+% We want to write the report to _OutputStream, but the library doesn't
+% support that yet.
+%
+% The stats are needed only when writing the deep profiling paper anyway.
+
+maybe_report_stats(yes(_OutputStream)) --> [].
+ % io__report_stats("standard").
maybe_report_stats(no) --> [].
:- pred maybe_report_msg(maybe(io__output_stream)::in, string::in,
diff -u deep_profiler/timeout.m deep_profiler/timeout.m
--- deep_profiler/timeout.m 13 Nov 2002 12:15:12 -0000
+++ deep_profiler/timeout.m 18 Nov 2002 03:37:27 -0000
@@ -57,12 +57,14 @@
:- pred setup_timeout(int::in, io__state::di, io__state::uo) is det.
% Get the lock on the named mutex file if the bool is `no'.
+% (The mutex file exists iff some process holds the lock.)
% If the bool is `yes', meaning debugging is enabled, do nothing.
:- pred get_lock(bool::in, string::in,
io__state::di, io__state::uo) is det.
% Release the lock on the named mutex file if the bool is `no'.
+% (The mutex file exists iff some process holds the lock.)
% If the bool is `yes', meaning debugging is enabled, do nothing.
:- pred release_lock(bool::in, string::in,
@@ -83,14 +85,16 @@
:- pragma foreign_decl("C",
"
+#ifdef MR_DEEP_PROFILER_ENABLED
+
#include <sys/types.h>
#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
+#include <fcntl.h> /* for O_CREAT, O_EXCL */
#include <signal.h> /* for signal numbers */
#include <unistd.h> /* for alarm() */
-#include <stdlib.h> /* for atexit() */
+#include <stdio.h>
#include <errno.h> /* for EEXIST etc */
+#include <dirent.h>
#include ""mercury_signal.h""
#define MP_MAX_CLEANUP_FILES 20 /* this should be plenty */
@@ -135,16 +139,15 @@
extern MR_bool MP_do_try_get_lock(const char *mutex_file);
extern void MP_do_get_lock(const char *mutex_file);
extern void MP_do_release_lock(const char *mutex_file);
+
+#endif
").
:- pragma foreign_code("C",
"
-#if defined(MR_HAVE_DIRENT_H)
- #include <sys/types.h>
- #include <dirent.h>
-#else
- /* if we get here, the deep profiler isn't enabled */
-#endif
+#ifdef MR_DEEP_PROFILER_ENABLED
+
+#include <sys/types.h>
const char *MP_cleanup_files[MP_MAX_CLEANUP_FILES];
int MP_cleanup_file_next = 0;
@@ -258,7 +261,7 @@
FILE *fp;
char buf[1024]; /* that should be big enough */
-#ifdef MP_DEBUG_SIGNAL
+#ifdef MP_DEBUG_MDPROF_SIGNAL
fp = fopen(""/tmp/mdprof_signal"", ""w"");
if (fp != NULL) {
fprintf(fp, ""%s\n"", signal_name);
@@ -268,7 +271,7 @@
MP_delete_cleanup_files();
-#ifdef MP_DEBUG_SIGNAL
+#ifdef MP_DEBUG_MDPROF_SIGNAL
sprintf(buf, ""Mercury deep profiler: received unexpected signal %s"",
signal_name);
MR_fatal_error(buf);
@@ -334,9 +337,6 @@
void
MP_handle_timeout(void)
{
-#if defined(MR_HAVE_DIRENT_H) && defined(MR_HAVE_OPENDIR) \
- && defined(MR_HAVE_READDIR) && defined(MR_HAVE_CLOSEDIR)
-
DIR *dir;
struct dirent *dirent;
int matchlen;
@@ -357,7 +357,7 @@
(void) alarm(MP_timeout_seconds);
return;
- }
+ }
dir = opendir(MP_timeout_want_dir);
if (dir == NULL) {
@@ -373,7 +373,7 @@
(void) alarm(MP_timeout_seconds);
return;
}
- }
+ }
(void) closedir(dir);
@@ -383,9 +383,6 @@
MP_delete_cleanup_files();
exit(EXIT_SUCCESS);
-#else
- /* if we get here, the deep profiler isn't enabled */
-#endif
}
void
@@ -494,38 +491,56 @@
MP_unregister_cleanup_file(mutex_file);
(void) unlink(mutex_file);
}
+
+#endif /* MR_DEEP_PROFILER_ENABLED */
").
:- pragma foreign_proc("C",
register_file_for_cleanup(File::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_register_cleanup_file(File);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
unregister_file_for_cleanup(File::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_unregister_cleanup_file(File);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
unregister_all_files_for_cleanup(S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_cleanup_file_next = 0;
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
delete_cleanup_files(S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_delete_cleanup_files();
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
@@ -533,6 +548,7 @@
S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
int i;
MP_timeout_mutex_file = MutexFile;
@@ -556,15 +572,22 @@
MR_register_exception_cleanup(MP_handle_fatal_exception, NULL);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
setup_timeout(Minutes::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_timeout_seconds = Minutes * 60;
(void) alarm(MP_timeout_seconds);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
%-----------------------------------------------------------------------------%
@@ -591,8 +614,12 @@
do_get_lock(MutexFile::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_do_get_lock(MutexFile);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pred do_release_lock(string::in, io__state::di, io__state::uo)
@@ -602,14 +629,19 @@
do_release_lock(MutexFile::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_do_release_lock(MutexFile);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
make_want_file(WantFileName::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
int fd;
fd = open(WantFileName, O_CREAT, 0);
@@ -621,11 +653,18 @@
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
:- pragma foreign_proc("C",
remove_want_file(WantFileName::in, S0::di, S::uo),
[will_not_call_mercury, promise_pure],
"
+#ifdef MR_DEEP_PROFILER_ENABLED
MP_unregister_cleanup_file(WantFileName);
(void) unlink(WantFileName);
S = S0;
+#else
+ MR_fatal_error(""deep profiler not enabled"");
+#endif
").
diff -u runtime/mercury_conf.h.in runtime/mercury_conf.h.in
--- runtime/mercury_conf.h.in 11 Nov 2002 10:44:59 -0000
+++ runtime/mercury_conf.h.in 16 Nov 2002 13:18:18 -0000
@@ -361,6 +361,11 @@
#undef MR_LITTLE_ENDIAN
/*
+** Do we have the O_CREAT and O_EXCL macros?
+*/
+#undef MR_HAVE_OCREAT_OEXCL
+
+/*
** Which version of Mercury is this? (Taken from the file ../VERSION.)
*/
#define MR_VERSION "unknown"
@@ -403,6 +408,14 @@
** See trace/mercury_trace_external.c.
*/
#undef MR_USE_EXTERNAL_DEBUGGER
+
+/*
+** MR_DEEP_PROFILER_ENABLED
+** Enable the deep profiler. This should be defined only if all the
+** features (header files and system calls) needed by the deep profiler
+** ara available on this platform.
+*/
+#undef MR_DEEP_PROFILER_ENABLED
/*
** MR_NO_USE_READLINE
diff -u runtime/mercury_misc.h runtime/mercury_misc.h
--- runtime/mercury_misc.h 13 Nov 2002 12:05:53 -0000
+++ runtime/mercury_misc.h 18 Nov 2002 02:51:39 -0000
@@ -27,8 +27,19 @@
extern void MR_fatal_error(const char *msg, ...) MR_NO_RETURN;
+/*
+** Register a function to be called (as func(data)) when the program is
+** about to be terminated due to an uncaught exception.
+*/
+
extern void MR_register_exception_cleanup(void (*func)(void *),
void *data);
+
+/*
+** Call all the functions registered with MR_register_exception_cleanup.
+** Should be invoked only when the program is about to be terminated
+** due to an uncaught exception.
+*/
extern void MR_perform_registered_exception_cleanups(void);
only in patch2:
--- tests/general/Mmakefile 14 Nov 2002 09:46:29 -0000 1.45
+++ tests/general/Mmakefile 16 Nov 2002 03:20:33 -0000
@@ -96,6 +96,8 @@
TESTS_DIR=..
include $(TESTS_DIR)/Mmake.common
+MCFLAGS += --no-optimize-duplicate-calls
+
# Module-specific options should go in Mercury.options so they
# can be found by `mmc --make'.
include Mercury.options
only in patch2:
--- scripts/Mmakefile 16 May 2002 06:48:43 -0000 1.27
+++ scripts/Mmakefile 14 Nov 2002 07:47:39 -0000
@@ -20,7 +20,6 @@
mercury.bat
DEBUGGER_SCRIPTS = mdbrc
EMACS_SCRIPTS = gud.el
-CGI_SCRIPTS = mdprof
#-----------------------------------------------------------------------------#
@@ -34,7 +33,7 @@
#-----------------------------------------------------------------------------#
.PHONY: all
-all: $(SCRIPTS) $(DEBUGGER_SCRIPTS) $(EMACS_SCRIPTS) $(CGI_SCRIPTS)
+all: $(SCRIPTS) $(DEBUGGER_SCRIPTS) $(EMACS_SCRIPTS)
all: Mmake.vars
#-----------------------------------------------------------------------------#
@@ -90,17 +89,6 @@
install_emacs_scripts: $(EMACS_SCRIPTS) install_dirs
cp $(EMACS_SCRIPTS) $(INSTALL_ELISP_DIR)
-.PHONY: install_cgi_scripts
-install_cgi_scripts: $(CGI_SCRIPTS)
- # $(INSTALL_CGI_DIR) is likely to be writeable only by root or
- # the www system administrator, which is why we don't consider a
- # failure of this action to be an error. If the command fails,
- # the install action in ../Mmakefile will remind the user to do
- # the copy later.
- -if test $(ENABLE_DEEP_PROFILER) = yes ; then \
- cp $(CGI_SCRIPTS) $(INSTALL_CGI_DIR) ; \
- fi
-
#-----------------------------------------------------------------------------#
.PHONY: uninstall
@@ -113,15 +101,6 @@
# on $(INSTALL_LIBDIR), and the directory into which $(EMACS_SCRIPTS)
# is installed, $(INSTALL_ELISP_DIR), is configured to be a
# subdirectory of $(INSTALL_LIBDIR).
- #
- # We try to uninstall $(CGI_SCRIPTS), but failure to do so is not an
- # error for two reasons: because we may simply lack permission to
- # update the directory, and because the deep profiler installation
- # may not have been enabled in the first place. (Looking at the current
- # value of $(ENABLE_DEEP_PROFILER) to check for the latter wouldn't
- # necessarily do any good, since its setting may have changed since
- # the original install.)
- -cd $(INSTALL_CGI_DIR) && rm $(CGI_SCRIPTS)
#-----------------------------------------------------------------------------#
only in patch2:
--- runtime/mercury_conf_param.h 16 Oct 2002 05:45:24 -0000 1.66
+++ runtime/mercury_conf_param.h 16 Nov 2002 12:30:04 -0000
@@ -227,6 +227,10 @@
** MR_DEBUG_LVAL_REP
** Enables low-level debugging messages from routines concerned with
** the representation of lvals in the RTTI system.
+**
+** MR_DEBUG_MDPROF_SIGNAL
+** Enables low-level debugging messages from the signal handling
+** functions in the deep profiler.
*/
#ifdef MR_HIGHLEVEL_CODE
only in patch2:
--- doc/user_guide.texi 15 Nov 2002 04:50:33 -0000 1.343
+++ doc/user_guide.texi 16 Nov 2002 03:19:52 -0000
@@ -3932,16 +3932,16 @@
To display the information contained in a deep profiling data file
(which will be called @file{Deep.data} unless you renamed it),
start up your browser and give it a URL of the form
- at file{http://server.domain.name/cgi-bin/mdprof?/full/path/name/Deep.data}.
+ at file{http://server.domain.name/cgi-bin/mdprof_cgi?/full/path/name/Deep.data}.
The @file{server.domain.name} part should be the name of a machine
with the following qualifications:
it should have a web server running on it,
-and it should have the @samp{mdprof} program installed
+and it should have the @samp{mdprof_cgi} program installed
in its @file{/usr/lib/cgi-bin} directory.
The @file{/full/path/name/Deep.data} part
should be the full path name of the deep profiling data file
whose data you wish to explore.
-The name of this file must not have dollar signs in it.
+The name of this file must not have percent signs in it.
@node Profiling and shared libraries
@section Profiling and shared libraries
only in patch2:
--- bindist/bindist.Makefile.in 8 Aug 2001 13:55:52 -0000 1.28
+++ bindist/bindist.Makefile.in 18 Nov 2002 03:40:24 -0000
@@ -1,5 +1,5 @@
#---------------------------------------------------------------------------#
-# Copyright (C) 1996-1999, 2001 The University of Melbourne.
+# Copyright (C) 1996-1999, 2001-2002 The University of Melbourne.
# This file may only be copied under the terms of the GNU General
# Public License - see the file COPYING in the Mercury distribution.
#---------------------------------------------------------------------------#
@@ -23,7 +23,9 @@
scripts/ml scripts/mmake scripts/mprof \
scripts/mdb scripts/mkfifo_using_mknod
-INSTALL_CGI_SCRIPTS = scripts/mdprof
+CGI_PROG_NAME = mdprof_cgi
+
+INSTALL_CGI_PROG = cgi/$(CGI_PROG_NAME)
INSTALL_EMACS_SCRIPTS = scripts/gud.el
@@ -57,18 +59,22 @@
@echo "-- The binary distribution does not need building."
@echo "-- Use \`make install' to install"
+# The code of the install rule is duplicated from the toplevel Mmakefile,
+# with minor changes.
+
.PHONY: install
install: install_lib install_info install_man \
- install_scripts install_emacs_scripts install_cgi_scripts \
+ install_scripts install_emacs_scripts install_cgi_progs \
install_mmake install_mdb install_util install_gac
@echo
@echo "-- Don't forget to add $(INSTALL_BINDIR) to your PATH,"
@echo "-- $(INSTALL_MAN_DIR) to your MANPATH,"
@echo "-- and $(INSTALL_INFODIR) to your INFOPATH,"
@if test $(ENABLE_DEEP_PROFILER) != yes || \
- cmp -s scripts/mdprof.in $(INSTALL_CGI_DIR)/mdprof; \
+ cmp -s $(INSTALL_CGI_PROG) \
+ $(INSTALL_CGI_DIR)/$(CGI_PROG_NAME); \
then true ; else \
- echo "-- to copy scripts/mdprof to $(INSTALL_CGI_DIR),"; \
+ echo "-- to copy $(INSTALL_CGI_PROG) to $(INSTALL_CGI_DIR),"; \
fi
@echo "-- and to add the following lines to the \`.emacs' file"
@echo "-- in your home directory:"
@@ -118,15 +124,25 @@
test -d $(INSTALL_ELISP_DIR) || mkdir -p $(INSTALL_ELISP_DIR)
cp $(INSTALL_EMACS_SCRIPTS) $(INSTALL_ELISP_DIR)
-.PHONY: install_cgi_scripts
-install_cgi_scripts: $(INSTALL_CGI_SCRIPTS)
+# The code of the install_cgi_progs target is duplicated from the code
+# of the install_cgi_progs target in deep_profiler/Mmakefile. However,
+# they refer to the script by different paths.
+
+.PHONY: install_cgi_progs
+install_cgi_progs: $(INSTALL_CGI_PROG)
# $(INSTALL_CGI_DIR) is likely to be writeable only by root or
# the www system administrator, which is why we don't consider a
# failure of this action to be an error. If the command fails,
- # the action for the `install' target will remind the user
- # to do the copy later.
+ # the install action in ../Mmakefile will remind the user to do
+ # the copy later.
+ #
+ # The mv before the cp is there in case the executable is being
+ # executed when we do the install. The mv is of course expected to
+ # fail during a first-time installation.
-if test $(ENABLE_DEEP_PROFILER) = yes ; then \
- cp $(INSTALL_CGI_SCRIPTS) $(INSTALL_CGI_DIR) ; \
+ mv $(INSTALL_CGI_DIR)/$(CGI_PROG_NAME) \
+ $(INSTALL_CGI_DIR)/$(CGI_PROG_NAME).was ; \
+ cp $(INSTALL_CGI_PROG) $(INSTALL_CGI_DIR) ; \
fi
.PHONY: install_mmake
only in patch2:
--- bindist/Mmakefile 4 Nov 2002 06:30:39 -0000 1.34
+++ bindist/Mmakefile 14 Nov 2002 07:41:17 -0000
@@ -33,6 +33,8 @@
../scripts/canonical_grade \
../scripts/gud.el
+CGI_PROG = ../deep_profiler/mdprof_cgi
+
VIM_FILES = ../vim/*
CONFIG_FILES = ../config.sub ../config.guess ../install-sh
@@ -73,6 +75,8 @@
cp $(SCRIPT_FILES) $(MERCURY_VERSION)/scripts
test -d $(MERCURY_VERSION)/util || mkdir $(MERCURY_VERSION)/util
cp $(UTILS) $(MERCURY_VERSION)/util
+ test -d $(MERCURY_VERSION)/cgi || mkdir $(MERCURY_VERSION)/cgi
+ cp $(CGI_PROG) $(MERCURY_VERSION)/cgi
test -d $(MERCURY_VERSION)/vim || mkdir $(MERCURY_VERSION)/vim
cp -R $(VIM_FILES) $(MERCURY_VERSION)/vim
cp $(CONFIG_FILES) $(MERCURY_VERSION)
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list